Android:小部件配置活动两次推出?

时间:2011-01-13 14:39:41

标签: android android-activity android-widget android-intent

我有一个具有配置活动的Android小部件。我还在小部件上设置了一个ImageView“按钮”来启动配置活动,以防用户在初始化后想要更改他/她的首选项。

所以,基本生命周期:

  1. 用户添加小部件
  2. 弹出配置活动,用户填写字段并点击“提交”
  3. 小部件已添加到屏幕上
  4. 用户点击ImageView以启动配置活动
  5. 弹出配置活动,用户编辑字段
  6. 点击“提交”或退出后,小部件会更新
  7. 用户可以根据需要继续执行第5步和第6步。
  8. 我的问题在第5步。第一次第一次用户点击ImageView时,看起来启动了两个配置活动。也就是说,当我退出第一个时,还有一个“落后”它。然而,在配置活动的所有后续启动中,只启动了一个,一切都很好。

    可能是什么问题?我将在下面发布相关代码。

    的AndroidManifest.xml

        <activity
            android:name=".ConfigActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
            </intent-filter>
        </activity>
        <receiver
            android:name=".Widget"
            android:label="Widget" >
            <intent-filter>
                <action
                    android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <intent-filter>
                <action
                    android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                    <data android:scheme="sample_widget" />
            </intent-filter>
            <intent-filter>
                <action
                    android:name="com.this.that.WIDGET_CONTROL" />
                <data
                    android:scheme="sample_widget" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/widget" />
        </receiver>
    

    AppWidget-Provider widget.xml

    <?xml version="1.0" encoding="utf-8"?>
    <appwidget-provider
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:updatePeriodMillis="5000"
        android:minWidth="294dp"
        android:minHeight="220dp"
        android:initialLayout="@layout/widgetlayout"
        android:configure="com.this.that.ConfigActivity" >
    </appwidget-provider>
    

    ConfigActivity.java

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        // Get the data we were launched with
        Intent launchIntent = getIntent();
        Bundle extras = launchIntent.getExtras();
        if (extras != null) {
            appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
    
            Intent cancelResultValue = new Intent();
            cancelResultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            setResult(RESULT_CANCELED, cancelResultValue);
        } else {
            // Only launch if it's for configuration
            finish();
        }
    
        setContentView(R.layout.myconfig);
    
        // Create Buttons/EditTexts
        SubmitBTN = (Button) findViewById(R.id.BTNSubmit);
        SampleET= (EditText) findViewById(R.id.ETSample);
        SubmitBTN.setOnClickListener(submitListener);
    
        loadPreferences(ConfigActivity.this, appWidgetId);
    }
    
    private OnClickListener submitListener = new OnClickListener() {
        public void onClick(View v) {
            final Context context = PriorityViewConfig.this;
    
            // Save strings in our prefs
            String sample = SampleET.getText().toString();
            SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
            prefs.putString(PREF_PREFIX_KEY + appWidgetId + "sample", sample);
            prefs.commit();
    
            if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
                // Tell the AppWidgetManager that we're now configured
                Intent resultValue = new Intent();
                //resultValue.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
                resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
                setResult(RESULT_OK, resultValue);
    
                // Get an instance of the AppWidgetManager
                AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    
                // Update the App Widget with the layout
                RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
                Widget.updateDisplayState(context, appWidgetId);
            }
    
            // Activity is now done
            finish();
        }
    };
    
    private void loadPreferences(Context context, int appWidgetId) {
        SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
        String sample = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "sample", null);
    
        if (sample != null) {
            SampleET.setText(sample);
        } else {
            // Nothing stored, don't need to do anything
        }
    }
    

    Widget.java

    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        Log.d(LOG_TAG, "OnReceive:Action: " + action);
    
        if (ACTION_WIDGET_CONTROL.equals(action)) {
            // Pass this on to the action handler where we'll figure out what to do and update the widget
            final int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
            if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
                this.onHandleAction(context, appWidgetId, intent.getData());
            }           
        }
        super.onReceive(context, intent);
    }
    
    public static void updateDisplayState(Context context, int appWidgetId) {
        Intent configIntent = new Intent(context, ConfigActivity.class);
        configIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        // Make this unique for this appWidgetId
        configIntent.setData(Uri.withAppendedPath(Uri.parse(Widget.URI_SCHEME + "://widget/id/"), String.valueOf(appWidgetId)));
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, configIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        views.setOnClickPendingIntent(R.id.IVConfig, pendingIntent);
    
        AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId, views);
    }
    
    private void onHandleAction(Context context, int appWidgetId, Uri data) {
        String controlType = data.getFragment();        
        // Nothing here yet
        updateDisplayState(context, appWidgetId);
    }
    

    我认为这些是最相关的部分。我将要进一步研究的地方是在submitListener中的ConfigActivity.java和Widget.java中的updateDisplayState方法

    任何帮助都会很棒!谢谢!

2 个答案:

答案 0 :(得分:4)

调用显式意图时,应考虑使用其中一个意图标志(如FLAG_ACTIVITY_CLEAR_TOP)来保持堆栈的有序性。例如:

configIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

您可以在某些应用程序(如IMDB应用程序)中发现缺少此标记,其中每次单击“主页”按钮都会在堆栈上添加另一个主页活动实例,因此您需要多次单击“返回”按钮弹出堆栈并退出应用程序。:)

答案 1 :(得分:0)

添加到清单文件android的活动:noHistory =“true”和android:excludeFromRecents =“true”

它假设要解决问题

 <activity
    android:name=".ConfigActivity"
    android:label="@string/app_name" 
    android:noHistory="true" 
    android:excludeFromRecents="true">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
    </intent-filter>
</activity>