web-dev-qa-db-fra.com

cas de widget qui ne fonctionne pas avec Oreo 8.1 - message reçu: W/BroadcastQueue: exécution en arrière-plan non autorisée: réception

Mon application de widget fonctionne correctement sur toutes les versions d'Android, à l'exception de 8 Oreo . Je reçois un message W/BroadcastQueue: Background execution not allowed: receiving Intent.

CommonsWare propose un blog intéressant mais je ne comprends pas très bien pourquoi cela s'applique à mon cas. https://commonsware.com/blog/2017/04/11/Android-o-implicit-broadcast-ban.html

Mon cas a l'air assez simple: j'ai un widget avec un bouton et je veux changer le bouton du texte quand on clique dessus.

Quelle est la bonne façon de résoudre ce problème?

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>
7
narb

C’est subtil, mais c’est parce que implicit broadcast est utilisé pour déclencher votre TestWidgetReceiver. C'est implicite, car il ne s'agit que de spécifier la partie action de la variable Intent. Rendre la diffusion Intent explicit en spécifiant la classe du récepteur dans le constructeur:

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);
}
8
Larry Schiefer