【问题标题】:Android: Widget Config Activity Getting Launched Twice?Android:小部件配置活动启动两次?
【发布时间】:2011-01-13 14:39:41
【问题描述】:

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

所以,基本生命周期:

  1. 用户添加小部件
  2. 配置活动弹出,用户填写字段并点击“提交”
  3. 小部件已添加到屏幕上
  4. 用户点击 ImageView 以启动配置活动
  5. 配置活动弹出,用户编辑字段
  6. 点击“提交”或退出后,小部件会更新
  7. 用户可以根据需要继续执行第 5 步和第 6 步。

我的问题出现在第 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 方法

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

【问题讨论】:

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


    【解决方案1】:

    当调用显式意图时,您应该考虑使用诸如 FLAG_ACTIVITY_CLEAR_TOP 之类的意图标志之一来保持堆栈的有序性。例如:

    configIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    

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

    【讨论】:

      【解决方案2】:

      在清单文件 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>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-07-02
        • 1970-01-01
        • 2012-07-29
        • 2016-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多