Créer un widget avancé

Essayer la méthode Compose
Jetpack Compose est le kit d'UI recommandé pour Android. Découvrez comment créer des widgets à l'aide d'API de style Compose.

Cette page décrit 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 du widget

La mise à jour du contenu d'un widget peut s'avérer coûteuse en ressources de calcul. Pour économiser la batterie, optimisez le type, la fréquence et le moment des mises à 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 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.

val appWidgetManager = AppWidgetManager.getInstance(context)
val remoteViews = RemoteViews(context.packageName, R.layout.widgetlayout).apply {
    setTextViewText(R.id.textview_widget_layout1, "Updated text1")
    setTextViewText(R.id.textview_widget_layout2, "Updated text2")
}
appWidgetManager.updateAppWidget(appWidgetId, remoteViews)

val appWidgetManager = AppWidgetManager.getInstance(context)
val remoteViews = RemoteViews(context.packageName, R.layout.widgetlayout).apply {
    setTextViewText(R.id.textview_widget_layout, "Updated text")
}
appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews)

val 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 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 l'attribut updatePeriodMillis. Le widget peut se mettre à 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, tenez compte des alternatives pour les mises à jour du broadcast receiver décrites dans une section suivante si votre widget doit charger des données de manière asynchrone ou s'il met plus de 10 secondes à se mettre à jour, car après 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 mis à jour toutes les 15 minutes ou seulement quatre fois par jour. Dans ce cas, définissez updatePeriodMillis sur 0 et utilisez WorkManager à la place.

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.updateAppWidget en 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'élément Activity, Broadcast ou Service appelé. Vous pouvez choisir votre propre priorité. Par exemple, si vous sélectionnez un Broadcast pour le PendingIntent, vous pouvez choisir une diffusion au premier plan pour donner la priorité au BroadcastReceiver.

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 des tâches avec WorkManager et spécifier un déclencheur d'URI de contenu à l'aide de la méthode Constraints.Builder.addContentUriTrigger.

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 option 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 considérations suivantes 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 permet aux broadcast receivers, qui s'exécutent généralement dans le thread principal de l'application, de s'exécuter pendant 10 secondes maximum avant de les considérer comme non réactifs et de déclencher une erreur Application Not Responding (ANR). Pour éviter de bloquer le thread principal lors du traitement 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 de 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 la surcharge des ressources système peut entraîner un retard dans l'appel du broadcast receiver. Pour prioriser la diffusion, faites-en un processus de premier plan.

Par exemple, ajoutez l'indicateur Intent.FLAG_RECEIVER_FOREGROUND à l'Intent transmis à l'PendingIntent.getBroadcast lorsque l'utilisateur appuie sur une certaine partie du widget.