J'utilise Android. Je crée un objet PendingIntent
et l'utilise dans la méthode RemoteViews#setOnClickPendingIntent()
. C'est l'intention en attente:
// The below code is called in the onUpdate(Context, AppWidgetManager, int[]) method of the AppWidgetProvider class.
// Explicit intent
Intent intent = new Intent(context, MyService.class);
intent.setAction(MY_ACTION);
intent.putExtra(EXTRA_KEY, VALUE);
// Create the pending intent
PendingIntent pendingIntent = PendingIntent.getService(context, appWidgetId, intent, 0);
// 'views' is a RemoteViews object provided by onUpdate in the AppWidgetProvider class.
views.setOnClickPendingIntent(R.id.root_layout, pendingIntent);
Le code ci-dessus fonctionne comme prévu avant Android Oreo. Cependant, dans Android Oreo, il ne démarre plus le service si l'application est balayée des recents. (No PendingIntent
s ne sont-ils pas exclus des limites d'exécution en arrière-plan d'Oreo?
À des fins de test, j'ai remplacé getService
par getForegroundService
mais le Service
n'est toujours pas démarré. Les deux méthodes affichent le message ci-dessous dans le journal:
W/ActivityManager: Background start not allowed: service Intent { act=com.example.myapp.MY_ACTION flg=0x10000000 cmp=com.example.myapp/com.example.myapp.MyService bnds=[607,716][833,942] (has extras) } to com.example.myapp/com.example.myapp.MyService from pid=-1 uid=10105 pkg=com.example.myapp
Pourquoi le Service
n'est-il pas démarré, même lorsque vous utilisez getForegroundService
? J'ai testé cela sur un Nexus 6P exécutant Android 8.1.0.
Comme vous le constatez, un widget d'application ne compte pas pour la liste blanche d'arrière-plan PendingIntent
. Je ne sais pas pourquoi - il semblerait être à peu près au même niveau qu'un PendingIntent
démarré par un Notification
. C'est peut-être un problème que le Notification
est une chose système, tandis que le widget de l'application est une chose de l'écran d'accueil. Quoi qu'il en soit, vous pourriez:
Utilisez getForegroundService()
, comme vous l'avez fait, ou
Essayez getBroadcast()
avec un Intent
explicite, et avec le BroadcastReceiver
commençant un JobIntentService
, si vous ne voulez pas soulever un Notification
(comme un service de premier plan l'exige)
Sur la base de vos symptômes, vous semblez avoir trébuché sur ce que je considérerais comme un bug: il devrait y avoir un moyen de passer de getService()
à getForegroundService()
sans avoir à redémarrer. :-) J'essaierai d'exécuter quelques expériences et déposerai un problème si je peux reproduire le problème.
Vous ne pouvez plus démarrer un service en arrière-plan dans 8.0, mais vous pouvez utiliser JobScheduler
pour obtenir des résultats similaires. Il existe également une classe d'assistance JobIntentService
qui vous permet de basculer vers JobScheduler
à partir du service sans trop de refactorisation. Et vous ne pouvez pas utiliser PendingIntent
pointant vers un service, mais vous pouvez en utiliser un pointant vers Activity
ou BroadcastReceiver
.
Si vous aviez un widget fonctionnel avant 8.0, et maintenant vous devez le faire fonctionner sur Android 8.0, effectuez simplement ces étapes simples:
IntentService
en JobIntentService
onHandleIntent
en onHandleWork
(mêmes paramètres)BIND_JOB_SERVICE
autorisation de votre service dans le manifeste: <service Android:name=".widget.MyWidgetService"
Android:permission="Android.permission.BIND_JOB_SERVICE">
</service>
enqueueWork
(où JOB_ID est juste une constante entière unique, doit être la même valeur pour tous les travaux mis en file d'attente pour la même classe): enqueueWork(context, MyWidgetService.class, JOB_ID, intent);
Intent myIntent = new Intent(context, MyAppWidgetProvider.class);
myIntent .setAction("SOME_UNIQUE_ACTION");
pendingIntent = PendingIntent.getBroadcast(context, 0, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent
démarrait le activity
, laissez-le tranquille - cela fonctionnera très bien sur Android 8.0+ ): @Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if (intent.getAction().equals("SOME_UNIQUE_ACTION")) {
MyWidgetService.enqueueWork(.....);
}
}
widget
fonctionnera sur les anciens appareils, assurez-vous que vous disposez de l'autorisation WAKE_LOCK dans votre manifeste (utilisée par JobIntentService
sur les anciens appareils).C'est ça. Ce widget fonctionnera désormais correctement sur les nouveaux et les anciens appareils. La seule vraie différence sera que si votre appareil 8.0 est en mode somnolence, il ne peut pas mettre à jour le widget très souvent, mais cela ne devrait pas être un problème car s'il somnole, cela signifie que l'utilisateur ne peut pas voir votre widget pour le moment de toute façon.
Est-ce que goasyc pourrait être une option? Vous pouvez modifier votre PendingIntent pour déclencher un BroadcastReceiver, puis dans la méthode OnRecieve, vous pouvez appeler goasync () Ensuite, vous devriez pouvoir utiliser le PendingResult qu'il génère pour créer un appel asynchrone. Ne pensez toujours pas que vous pouvez démarrer un service.