小部件案例不适用于Oreo 8.1 - 收到的消息:W / BroadcastQueue:不允许后台执行:接收Intent

时间:2018-06-17 07:23:39

标签: android android-widget

我的小部件应用程序在除8 Oreo之外的所有Android版本上运行正常。 我收到W/BroadcastQueue: Background execution not allowed: receiving Intent消息。

CommonsWare有一个有趣的博客,但我不完全理解为什么它适用于我的情况。 https://commonsware.com/blog/2017/04/11/android-o-implicit-broadcast-ban.html

我的案例看起来非常简单:我有一个带按钮的小部件,我想在点击它时更改文本的按钮。

解决此问题的正确方法是什么?

TestWidget.java

public class TestWidget extends AppWidgetProvider {
    private static RemoteViews views;
    private static boolean buttonClicked = false;
    public static final String ACTION_AUTO_UPDATE = "AUTO_UPDATE";

    @Override
    public void onReceive(Context context, Intent intent)
    {
        super.onReceive(context, intent);

        if(intent.getAction().equals(ACTION_AUTO_UPDATE))
        {
                Log.i("TESTWID", "get onReceive");
        }
    }

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                int appWidgetId) {
        views = new RemoteViews(context.getPackageName(), R.layout.test_widget);
        views.setOnClickPendingIntent(R.id.wid_btn_tst, setButton(context));

        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        Log.i("TESTWID", "onupdate ");

        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
    }

    public static PendingIntent setButton(Context context) {
        Intent intent = new Intent();
        intent.setAction("TEST");
        return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    public static void pushWidgetUpdate(Context context, RemoteViews remoteViews) {
        ComponentName myWidget = new ComponentName(context, TestWidget.class);
        AppWidgetManager manager = AppWidgetManager.getInstance(context);
        manager.updateAppWidget(myWidget, remoteViews);
    }

}

TestWidgetReceiver.java

public class TestWidgetReceiver extends BroadcastReceiver{
    private static boolean isButtonON = false;

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("TESTWID", "onReceive "+intent.getAction());

        if(intent.getAction().equals("TEST")){
            updateWidgetButton(context, 2);
        }
    }

    private void updateWidgetButton(Context context, int index) {
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.test_widget);
        if(index == 2) {
            if(isButtonON) {
                remoteViews.setTextViewText(R.id.wid_btn_tst, "Test Off");
                isButtonON = false;
            }
            else{
                remoteViews.setTextViewText(R.id.wid_btn_tst, "Test On");
                isButtonON = true;
            }
        }

        TestWidget.pushWidgetUpdate(context.getApplicationContext(), remoteViews);
    }

}

的Manifest.xml:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="Test"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver android:name=".TestWidget">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <intent-filter>
                <action android:name="AUTO_UPDATE" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/test_widget_info" />
        </receiver>

        <receiver
            android:name=".TestWidgetReceiver"
            android:label="widgetBroadcastReceiver" >
            <intent-filter>
                <action android:name="TEST" />
            </intent-filter>

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

    </application>

2 个答案:

答案 0 :(得分:11)

这很微妙,但这是因为隐式广播被用来触发您的TestWidgetReceiver。它是隐式的,因为它仅指定Intent的操作部分。通过在构造函数中指定接收器类,使广播Intent 显式

public static PendingIntent setButton(Context context) {
    Intent intent = new Intent(context, TestWidgetReceiver.class);
    intent.setAction("TEST");
    return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}

答案 1 :(得分:1)

现在在Android设备上发生了变化。为了提高安全性和电池消耗,Google引入了许多方法并给开发人员增加了一些问题。 您尚未将TestWidgetReceiver.class的上下文传递给您的意图。

您可以像在Java中那样

Intent intent = new Intent(context, TestWidgetReceiver.class);

或科特林

val intent = Intent(context, TestWidgetReceiver.class);

您可以在此处阅读更多更改

https://developer.android.com/about/versions/oreo/android-8.0-changes

致谢