带集合的 AppWidget - 单击小部件时无法 运行 配置 Activity

AppWidget with collection - can`t run Config Activity when clicking on widget

我遇到了 Whosebug 上非常流行的问题,并且有很多解决方法。但不幸的是,它们都不适合我。

我使用集合 (StackView) 创建了 appWidget,添加了 ConfigActivity 用于配置和具有指定时间间隔的永久更新机制。小部件以正确的方式显示,更新工作正常,但是当我想要 运行 配置 Activity 并单击小部件时 - 没有任何反应!

也许,我错过了一些重要的细节,希望你能给我建议。以下是一些代码片段:

清单

<uses-sdk android:minSdkVersion="11"
    android:targetSdkVersion="22"/>

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<application
    android:name=".FinApp"
    android:allowBackup="true"
    android:icon="@mipmap/ic_fin"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

    <receiver android:name=".widget.WidgetProvider" >
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>

        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/fin_app_widget_info" />
    </receiver>

    <activity android:name=".ConfigActivity"
        android:screenOrientation="portrait">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
        </intent-filter>
    </activity>

    <service
        android:name=".widget.WidgetService"
        android:permission="android.permission.BIND_REMOTEVIEWS"/>

</application>

AppWidgetProvider

public class WidgetProvider extends AppWidgetProvider {
private static final String TAG = WidgetProvider.class.getSimpleName();

@Override
public void onReceive(Context context, Intent intent) {
    Log.i(TAG, "onReceive");
    super.onReceive(context, intent);
}

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    Log.w(TAG, "onUpdate: appWidgetIds - " + Arrays.toString(appWidgetIds));

    for (int id : appWidgetIds) {
        updateAppWidgetInstance(context, appWidgetManager, id);
    }
}

public static void updateWidgetsOnDataSetChanged (Context context) {
    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    int[] appWidgetIds = appWidgetManager.getAppWidgetIds(
            new ComponentName(context.getPackageName(), WidgetProvider.class.getName()));

    appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_list);
}

private static void addWidgetListener(Context context, int appWidgetId, RemoteViews widget) {
    Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));

    PendingIntent runConfigActivity = PendingIntent.getActivity(context, 0, intent,
            PendingIntent.FLAG_UPDATE_CURRENT);

    widget.setOnClickPendingIntent(R.id.widget_container, runConfigActivity);
}

private static void setupWidgetService(Context context, int appWidgetId, RemoteViews widget) {
    Intent adapterIntent = new Intent(context, WidgetService.class);
    adapterIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    adapterIntent.setData(Uri.fromParts("content", String.valueOf(appWidgetId), null));

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        widget.setRemoteAdapter(R.id.widget_list, adapterIntent);
    } else {
        //noinspection deprecation
        widget.setRemoteAdapter(appWidgetId, R.id.widget_list, adapterIntent);
    }
}

private static void updateAppWidgetInstance(Context context, AppWidgetManager appWidgetManager,
                                           int appWidgetId) {
    Log.e(TAG, "updateAppWidgetInstance");

    RemoteViews widget = new RemoteViews(context.getPackageName(), R.layout.widget_collection_layout);
    setupWidgetService(context, appWidgetId, widget);
    addWidgetListener(context, appWidgetId, widget);

    appWidgetManager.updateAppWidget(appWidgetId, widget);
}

}

widget_collection_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/widget_container"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <StackView
        android:id="@+id/widget_list"
        android:loopViews="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

据我了解,重点在于方法 addWidgetListener

    private static void addWidgetListener(Context context, int appWidgetId, RemoteViews widget) {

    Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));

    PendingIntent runConfigActivity = PendingIntent.getActivity(context, 0, intent,
            PendingIntent.FLAG_UPDATE_CURRENT);

    widget.setOnClickPendingIntent(R.id.widget_container, runConfigActivity);
}

但我不知道哪里出了问题...

经过一些调查,我得出一个结论,如果我在 appWidget 中使用集合并想要打开 Config Activity 轻敲整个小部件容器,那么最佳做法是使用 setPendingIntentTemplate 方法,即使您不想处理项目点击,而是处理整个列表(列表容器)。

    private static void addWidgetListener(Context context, int appWidgetId, RemoteViews widget) {
    Intent intent = new Intent(context, ConfigActivity.class);
    intent.setAction(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);

    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

    intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));

    PendingIntent runConfigActivity = PendingIntent.getActivity(context, 0, intent,
            PendingIntent.FLAG_UPDATE_CURRENT);

    widget.setPendingIntentTemplate(R.id.widget_list, runConfigActivity);
}

并在方法 getViewAt(int position)

WidgetFactory 中添加 2 行
    Intent intent = new Intent();
    views.setOnClickFillInIntent(R.id.widget_item_container, intent);