代码之家  ›  专栏  ›  技术社区  ›  narb

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

  •  7
  • narb  · 技术社区  · 6 年前

    我的widget应用程序在所有android版本上运行良好,除了8 oreo。 我得到了 W/BroadcastQueue: Background execution not allowed: receiving Intent 消息。

    有一个来自Commonware的有趣博客,但我不完全理解为什么它适用于我的案例。 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);
        }
    
    }
    

    testwidgetceiver.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 回复  |  直到 6 年前
        1
  •  14
  •   Larry Schiefer    6 年前

    这很微妙,但这是因为 隐性的 用于触发 TestWidgetReceiver . 它是隐式的,因为它只指定 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);
    }
    
        2
  •  1
  •   Shivam Mathur    6 年前

    在安卓系统中,事情已经改变了。对于安全性和电池消耗,谷歌推出了很多方法,给开发者增加了一些问题。 你还没有通过 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

    当做