Cette page explique les pratiques recommandées pour créer un widget plus avancé et 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 calendrier des mises à jour.
Types de mises à jour des 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 ramifications différents.
Vous trouverez ci-dessous une description de chaque type de mise à jour, ainsi que 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 leRemoteViews
fourni précédemment par un nouveauRemoteViews
. Il s'agit de la mise à jour la plus coûteuse en termes 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.partiallyUpdateAppWidget
pour mettre à jour des parties du widget. Cela fusionne le nouveauRemoteViews
avec leRemoteViews
fourni précédemment. 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.notifyAppWidgetViewDataChanged
pour invalider les données d'une vue de collection dans votre widget. Cela déclencheRemoteViewsFactory.onDataSetChanged
. En attendant, les anciennes données s'affichent dans le widget. Cette méthode vous permet d'effectuer des tâches coûteuses de manière synchrone en toute sécurité.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 depuis n'importe quel endroit de votre application, à condition que l'application ait le même UID que la classe AppWidgetProvider
correspondante.
Déterminer la fréquence d'actualisation d'un widget
Les widgets sont mis à jour régulièrement en fonction de la valeur fournie pour l'attribut updatePeriodMillis
. Le widget peut se mettre à jour en réponse à une interaction de l'utilisateur, diffuser des mises à jour ou les deux.
Mises à jour régulières
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()
, qui est l'endroit où vous pouvez placer le code pour mettre à jour le widget. Toutefois, tenez compte des alternatives pour les mises à jour du récepteur de diffusion décrites dans une section suivante si votre widget doit charger des données de manière asynchrone ou met plus de 10 secondes à se mettre à jour, car au-delà de 10 secondes, le système considère qu'un BroadcastReceiver
ne répond pas.
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 ticker boursier soit actualisé toutes les 15 minutes ou seulement quatre fois par jour. Dans ce cas, définissez updatePeriodMillis
sur 0 et utilisez plutôt WorkManager
.
Mise à 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 :
Depuis une activité de l'application : appelez directement
AppWidgetManager.updateAppWidget
en réponse à une interaction de l'utilisateur, comme un appui.À partir d'interactions à distance, comme une notification ou un widget d'application : construisez un
PendingIntent
, puis mettez à jour le widget à partir de l'Activity
,Broadcast
ouService
invoqué. Vous pouvez choisir votre propre priorité. Par exemple, si vous sélectionnez unBroadcast
pour lePendingIntent
, vous pouvez choisir une diffusion au premier plan pour donner la priorité auBroadcastReceiver
.
Mettre à jour en réponse à un événement de diffusion
Par exemple, lorsqu'un utilisateur prend une photo, un événement de diffusion nécessite la mise à jour d'un widget. Dans ce cas, vous souhaitez mettre à jour le widget lorsqu'une nouvelle photo est détectée.
Vous pouvez planifier un job avec JobScheduler
et spécifier une diffusion comme déclencheur à l'aide de la méthode JobInfo.Builder.addTriggerContentUri
.
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 fonctionnalité avec précaution et n'écoutez que la diffusion spécifique. Avec l'introduction des limitations 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 maximum avant de les considérer comme non réactifs 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 méthode goAsync
. 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 Considérations et bonnes pratiques en matière de sécurité.
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'appel du récepteur de diffusion. Pour donner la priorité à la diffusion, faites-en un processus de premier plan.
Par exemple, ajoutez l'indicateur Intent.FLAG_RECEIVER_FOREGROUND
à Intent
transmis à PendingIntent.getBroadcast
lorsque l'utilisateur appuie sur une certaine partie du widget.