Cette page explique les pratiques recommandées pour créer un widget plus avancé afin d'améliorer l'expérience utilisateur.
Optimisations pour la mise à jour du contenu des widgets
La mise à jour du contenu des widgets peut s'avérer coûteuse en ressources de calcul. Pour économiser la batterie, optimisez le type, la fréquence et le moment de la mise à jour.
Types de mises à jour de widgets
Il existe trois façons de mettre à jour un widget : une mise à jour complète, une mise à jour partielle et, dans le cas d'un widget de collection, une actualisation des données. Chacune a des coûts de calcul et des conséquences différents.
La section suivante décrit chaque type de mise à jour et fournit des extraits de code pour chacun d'eux.
Mise à jour complète : appelez
AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews)pour mettre à jour complètement le widget. Cela remplace le précédemment fourniRemoteViewspar un nouveauRemoteViews. Il s'agit de la mise à jour la plus coûteuse en ressources de calcul.Kotlin
val appWidgetManager = AppWidgetManager.getInstance(context) val remoteViews = RemoteViews(context.getPackageName(), R.layout.widgetlayout).also { setTextViewText(R.id.textview_widget_layout1, "Updated text1") setTextViewText(R.id.textview_widget_layout2, "Updated text2") } appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
Java
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout); remoteViews.setTextViewText(R.id.textview_widget_layout1, "Updated text1"); remoteViews.setTextViewText(R.id.textview_widget_layout2, "Updated text2"); appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
Mise à jour partielle : appelez
AppWidgetManager.partiallyUpdateAppWidgetpour mettre à jour des parties du widget. Cela fusionne le nouveauRemoteViewsavec leRemoteViewsprécédemment fourni. Cette méthode est ignorée si un widget ne reçoit pas au moins une mise à jour complète viaupdateAppWidget(int[], RemoteViews).Kotlin
val appWidgetManager = AppWidgetManager.getInstance(context) val remoteViews = RemoteViews(context.getPackageName(), R.layout.widgetlayout).also { setTextViewText(R.id.textview_widget_layout, "Updated text") } appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews)
Java
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout); remoteViews.setTextViewText(R.id.textview_widget_layout, "Updated text"); appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews);
Actualisation des données de la collection : appelez
AppWidgetManager.notifyAppWidgetViewDataChangedpour invalider les données d'une vue de collection dans votre widget. Cela déclencheRemoteViewsFactory.onDataSetChanged. En attendant, les anciennes données sont affichées dans le widget. Vous pouvez effectuer des tâches coûteuses de manière synchrone avec cette méthode.Kotlin
val appWidgetManager = AppWidgetManager.getInstance(context) appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
Java
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview);
Vous pouvez appeler ces méthodes n'importe où dans votre application, à condition qu'elle ait le
même UID que la classe
AppWidgetProvider correspondante.
Déterminer la fréquence de mise à jour d'un widget
Les widgets sont mis à jour régulièrement en fonction de la valeur fournie pour le
updatePeriodMillis
attribut. Le widget peut être mis à jour en réponse à une interaction de l'utilisateur, à des mises à jour de diffusion ou aux deux.
Mettre à jour régulièrement
Vous pouvez contrôler la fréquence de la mise à jour périodique en spécifiant une valeur pour AppWidgetProviderInfo.updatePeriodMillis dans le fichier XML appwidget-provider. Chaque mise à jour déclenche la méthode AppWidgetProvider.onUpdate(), dans laquelle vous pouvez placer le code pour mettre à jour le widget. Toutefois, si votre widget doit charger des données de manière asynchrone ou prend plus
de 10 secondes pour se mettre à jour, envisagez les alternatives pour
les mises à jour du broadcast receiver décrites dans une
section suivante. En effet, après 10 secondes, le système considère qu'un
BroadcastReceiver ne répond plus.
updatePeriodMillis n'accepte pas les valeurs inférieures à 30 minutes. Toutefois, si vous souhaitez désactiver les mises à jour périodiques, vous pouvez spécifier 0.
Vous pouvez autoriser les utilisateurs à ajuster la fréquence des mises à jour dans une configuration. Par exemple, ils peuvent souhaiter qu'un téléscripteur boursier soit mis à jour toutes les 15 minutes ou seulement quatre fois par jour. Dans ce cas, définissez updatePeriodMillis sur 0 et utilisez
WorkManager plutôt.
Mettre à jour en réponse à une interaction de l'utilisateur
Voici quelques méthodes recommandées pour mettre à jour le widget en fonction de l'interaction de l'utilisateur :
À partir d'une activité de l'application : appelez directement
AppWidgetManager.updateAppWidgeten réponse à une interaction de l'utilisateur, par exemple un appui.À partir d'interactions à distance, telles qu'une notification ou un widget d'application : créez un
PendingIntent, puis mettez à jour le widget à partir de l'Activity, de laBroadcastou duServiceinvoqué. Vous pouvez choisir votre propre priorité. Par exemple, si vous sélectionnez unBroadcastpour lePendingIntent, vous pouvez choisir une diffusion au premier plan pour donner laBroadcastReceiverpriorité.
Mettre à jour en réponse à un événement de diffusion
Un exemple d'événement de diffusion qui nécessite la mise à jour d'un widget est celui où l'utilisateur prend une photo. Dans ce cas, vous devez mettre à jour le widget lorsqu'une nouvelle photo est détectée.
Vous pouvez planifier une tâche avec JobScheduler et spécifier une diffusion comme
déclencheur à l'aide de la
JobInfo.Builder.addTriggerContentUri
méthode.
Vous pouvez également enregistrer un BroadcastReceiver pour la diffusion, par exemple,
en écoutant
ACTION_LOCALE_CHANGED.
Toutefois, comme cela consomme des ressources de l'appareil, utilisez cette méthode avec précaution et n'écoutez que la diffusion spécifique. Avec l'introduction des limites
de diffusion dans Android
7.0 (niveau d'API 24) et Android 8.0 (niveau d'API 26), les applications ne peuvent pas enregistrer de diffusions implicites
dans leurs fichiers manifestes, à quelques
exceptions près.
Éléments à prendre en compte lors de la mise à jour d'un widget à partir d'un BroadcastReceiver
Si le widget est mis à jour à partir d'un BroadcastReceiver, y compris AppWidgetProvider, tenez compte des éléments suivants concernant la durée et la priorité d'une mise à jour de widget.
Durée de la mise à jour
En règle générale, le système autorise les récepteurs de diffusion, qui s'exécutent généralement dans le thread principal
de l'application, à s'exécuter pendant 10 secondes au maximum avant de les considérer comme ne répondant plus et
de déclencher une erreur "Application ne
répond pas" (ANR). Pour éviter de bloquer le
thread principal lors de la gestion de la diffusion, utilisez la
goAsync méthode. Si la mise à jour du widget prend
plus de temps, envisagez de planifier une tâche
à l'aide de WorkManager.
Caution: Any work you do here blocks further broadcasts until it completes,
so it can slow the receiving of later events.
Pour en savoir plus, consultez la section Éléments à prendre en compte concernant la sécurité et bonnes pratiques.
Priorité de la mise à jour
Par défaut, les diffusions, y compris celles effectuées à l'aide de AppWidgetProvider.onUpdate, s'exécutent en tant que processus en arrière-plan. Cela signifie que des ressources système surchargées peuvent entraîner un retard dans l'invocation du récepteur de diffusion. Pour donner la priorité à la diffusion, faites-en un processus de premier plan.
Par exemple, ajoutez l'
Intent.FLAG_RECEIVER_FOREGROUND
indicateur à l'Intent transmis au PendingIntent.getBroadcast lorsque l'utilisateur
appuie sur une certaine partie du widget.