Accueil » Tutoriels » Tuto sur App Widgets pour Android : Partie 2 : mettre à jour un widget

Tuto sur App Widgets pour Android : Partie 2 : mettre à jour un widget

Les widgets doivent toujours afficher les dernières informations disponibles et la fréquence de mise à jour dépend du type spécifique de données. Un widget météo n’a pas besoin d’une mise à jour très fréquente, contrairement au score d’un match de football ou au prix d’un titre spécifique.

Vous avez besoin d’un moyen d’appeler la méthode onUpdate () précédente à un intervalle de temps spécifique afin de créer les nouvelles RemoteView avec les nouvelles données.

Le dessin suivant vous donne une idée du processus :

Le problème est de savoir comment envoyer le message « J’ai besoin d’un rafraîchissement! » dans le widget.

La configuration de widget

Lorsque la fréquence de mise à jour dont vous avez besoin est supérieure à 30 minutes, vous n’avez pas besoin d’écrire de code, vous pouvez simplement utiliser le fichier de configuration coffee_logger_widget_info.xml de Android Studio généré dans le dossier res\xml.

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
  android:initialKeyguardLayout="@layout/coffee_logger_widget"
  android:initialLayout="@layout/coffee_logger_widget"
  android:minHeight="110dp"
  android:minWidth="180dp"
  android:previewImage="@drawable/example_appwidget_preview"
  android:resizeMode="horizontal|vertical"
  android:updatePeriodMillis="86400000"
  android:widgetCategory="home_screen">
  </appwidget-provider>

Le taux de rafraîchissement du widget est celui défini dans l’attribut android:updatePeriodMillis. La valeur par défaut est un jour en millisecondes.

Gestion des demandes de mises à jour

Si vous comprenez comment la plateforme Android gère les mises à jour de votre Widget, vous pouvez reproduire la même chose à volonté. L’assistant Android Studio a créé la classe CoffeeLoggerWidget qui étend AppWidgetProvider, mais nous n’avons pas réalisé qu’il s’agissait d’une implémentation particulière d’un BroadcastReceiver.

Vous pouvez voir cela en regardant les mises à jour faites par l’assistant au fichier AndroidManifest.xml :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.raywenderlich.android.coffeelogs">

  - - - -

  <receiver android:name=".CoffeeLoggerWidget">
    <intent-filter>
      <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>

    <meta-data
      android:name="android.appwidget.provider"
      android:resource="@xml/coffee_logger_widget_info" />
  </receiver>

  - - - -

</manifest>

En fonction de l’action de l’Intent spécifique, AppWidgetProvider distribue l’appel à une méthode différente. Le lancement d’un Intent avec l’action android.appwidget.action.APPWIDGET_UPDATE entraîne l’appel de la fonction onUpdate ().

C’est exactement ce que fait le système Android à l’intervalle défini dans le fichier de configuration coffee_logger_widget_info.xml. Cela signifie que la fonction updateAppWidget () est l’endroit idéal pour que le code s’exécute à chaque mise à jour.

Ajoutez donc la ligne suivante au début de la fonction :

val coffeeLoggerPersistence = CoffeeLoggerPersistence(context)

et changez widgetText pour prendre la valeur à partir de là :

val widgetText = coffeeLoggerPersistence.loadTitlePref().toString()

Bien ! Construisez et exécutez, et vous verrez que le widget met périodiquement à jour la valeur « gramsme ». C’est comme si quelqu’un a bu un peu trop de café :

Mettre à jour le widget manuellement

Si votre application a besoin de mettre à jour les données dans le widget plus fréquemment, vous avez déjà la solution : vous pouvez simplement et périodiquement lancer le même Intent que le système Android. Dans le cas de l’application Coffee Log, cela se produit chaque fois que l’utilisateur sélectionne un café dans l’application.

Ouvrez MainActivity et ajoutez le code suivant à la fin de refreshTodayLabel :

// Send a broadcast so that the Operating system updates the widget
// 1
val man = AppWidgetManager.getInstance(this)
// 2
val ids = man.getAppWidgetIds(
    ComponentName(this, CoffeeLoggerWidget::class.java))
// 3
val updateIntent = Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
// 4
updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
// 5
sendBroadcast(updateIntent)

Puisque ce code contient de nouveaux éléments, on va vous guider :

  1. Obtenez l’instance AppWidgetManager, qui est responsable de tous les Widgets installés.
  2. Demandez les identifiants de toutes les instances de votre widget (vous pouvez en ajouter plusieurs à votre écran d’accueil).
  3. Créez un Intent avec l’action android.appwidget.action.APPWIDGET_UPDATE demandant une mise à jour.
  4. Ajoutez les ID des widgets auxquels vous envoyez l’Intent en tant que extras de l’Intent pour la clé AppWidgetManager.EXTRA_APPWIDGET_IDS.
  5. Enfin, envoyez le message de diffusion.

Construisez et exécutez l’application pour vérifier que chaque fois que vous ajoutez du café, le widget met également à jour.

Communication via le service

Toutes les mises à jour nécessaires pour Widgets ne sont pas une conséquence d’une action de l’utilisateur. Les cas typiques sont les données d’un serveur via des événements d’interrogation périodique et de notification push. Dans de tels cas, la demande doit provenir d’un composant différent, que vous implémentez généralement en tant que service Android.

Choisissez Fichier\Nouveau\ Service\Service et remplacez le nom par CoffeeQuotesService.

Lorsque vous cliquez sur Terminer, Android studio génère pour vous un fichier Kotlin pour le service.

Dans CoffeeQuotesService, remplacez l’implémentation actuelle de onBind () par :

return null

Changez le type de retour de onBind pour être le null IBinder?.

Ajoutez ensuite cette fonction, qui est celle que le système Android appelle à chaque lancement du service Service :

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
  val appWidgetManager = AppWidgetManager.getInstance(this)
  val allWidgetIds = intent?.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS)
  //1
  if (allWidgetIds != null) {
    //2
    for (appWidgetId in allWidgetIds) {
      //3
      CoffeeLoggerWidget.updateAppWidget(this, appWidgetManager, appWidgetId)
    }
  }
  return super.onStartCommand(intent, flags, startId)
}

Vous avez déjà vu les deux premières lignes. Voici les autres :

  1. Vérifiez que le tableau de allWidgetIds était dans l’Intent.
  2. Créez une boucle dans la liste allWidgetIds.
  3. Mettez à jour chaque widget.

Maintenant, vous devez appeler ce service au lieu de mettre directement à jour le widget. Ouvrez CoffeeLoggerWidget et remplacez le contenu de onUpdate () par ce qui suit afin de démarrer le service :

val intent = Intent(context.applicationContext, CoffeeQuotesService::class.java)
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)
context.startService(intent)

Cela crée un Intent, place les ID du widget dans l’intent et démarre le service.

Dans l’objet compagnon, ajoutez la fonction suivante :

private fun getRandomQuote(context: Context): String {
  //1
  val quotes = context.resources.getStringArray(R.array.coffee_texts)
  //2
  val rand = Math.random() * quotes.size
  //3
  return quotes[rand.toInt()].toString()
}

Cette fonction génère un devis de café de façon aléatoire :

  1. Elle prend un tableau de devis à partir du fichier de chaînes
  2. Elle choisit un nombre de façon aléatoire
  3. Enfin, elle renvoie la chaîne à la position aléatoire

Après avoir obtenu la chaîne, mettez à jour le widget. Dans updateAppWidget (), ajoutez ceci avant le dernier appel :

views.setTextViewText(R.id.coffee_quote, getRandomQuote(context))

C’est tout. Chaque fois que le widget se met à jour, vous obtenez un nouveau devis !

Rendre personnel le widget

Les gens aiment personnaliser l’apparence et la fonctionnalité de leurs écrans d’accueil, et les widgets ne font pas exception. Vous devez prendre en compte qu’un widget à usage général n’apportera pas beaucoup de valeur à un utilisateur. Pour le rendre personnel, vous devez laisser les utilisateurs configurer leurs préférences et leurs configurations.

Auparavant, lorsque vous construisez la configuration d’un widget, vous avez appris qu’il peut y avoir un écran de configuration. Cette Activité est automatiquement lancée lorsque l’utilisateur ajoute un widget sur l’écran d’accueil. Notez que les préférences sont configurées par widget, car les utilisateurs peuvent ajouter plusieurs instances d’un widget. Il est préférable de penser à sauvegarder ces préférences avec l’id du widget.

Dans le projet Coffee Log, l’écran de configuration peut contenir une limite de quantité de café. Si l’utilisateur enregistre plus de café que la limite, le Widget deviendra un rose doux mais alarmant.

Créer un écran de préférences

L’écran de préférence pour un widget est une Activité. Allez au Nouveau\Activité\Activité vide dans le menu Fichier et modifiez les champs par ceci :

  • Nom de l’activité : CoffeeLoggerWidgetConfigureActivity
  • Nom de la mise en page (layout) : activity_coffee_logger_widget_configure

Assurez-vous que la case Activité du lanceur (Launcher Activity) n’est pas cochée et que le langage source est Kotlin.

Lorsque vous cliquez sur Terminer, Android Studio génère le code de la nouvelle Activité et un modèle pour le fichier de layout, avec l’ajout de l’enregistrement de l’Activité dans le fichier AndroidManifest.xml.

Maintenant, créez le layout pour l’écran de configuration. Ouvrez activity_coffee_logger_widget_configure.xml et ajoutez ce qui suit :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical"
  android:padding="16dp">

  <TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="8dp"
    android:labelFor="@+id/appwidget_text"
    android:text="@string/coffee_amount_limit" />

  <EditText
    android:id="@id/appwidget_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:inputType="number" />

  <Button
    android:id="@+id/add_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="8dp"
    android:text="@string/save_configuration" />
</LinearLayout>

Le layout n’a rien de compliqué : un TextView qui représente un label pour EditText, et un bouton pour l’utilisateur pour enregistrer les préférences.

Connaissez vos limites

Ouvrez CoffeeLoggerWidgetConfigureActivity et ajoutez les champs au-dessus de onCreate () (les développeurs placent généralement les champs au début de la classe) :

private lateinit var appWidgetText: EditText
private var appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID
private val coffeeLoggerPersistence = CoffeeLoggerPersistence(this)

Vous devrez utiliser ces champs plus tard pour enregistrer la valeur limite pour chaque widget.

Dans onCreate (), ajoutez le code suivant à la fin :

//1
appWidgetText = findViewById(R.id.appwidget_text)
//2
val extras = intent.extras
//3
appWidgetId = extras.getInt(
    AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID)
//4
setResult(Activity.RESULT_CANCELED)

Voici ce qu’a fait le code :

  1. Trouver l’EditText dans la mise en page.
  2. Obtenir les extras de l’Intent qui a lancé l’Activité.
  3. Extrayer l’appWidgetId du widget.
  4. S’assurer que si l’utilisateur n’appuie pas sur le bouton « Enregistrer la configuration », le widget n’est pas ajouté.

Enfin, vous devez enregistrer la configuration lorsque l’utilisateur appuie sur le bouton « Enregistrer la configuration ». Au-dessous de onCreate (), déclarez l’implémentation OnClickListener suivante :

private var onClickListener: View.OnClickListener = View.OnClickListener {
  // 1
  val widgetText = appWidgetText.text.toString()
  // 2
  coffeeLoggerPersistence.saveLimitPref(widgetText.toInt(), appWidgetId)
  // 3
  val resultValue = Intent()
  resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
  // 4
  setResult(RESULT_OK, resultValue)
  // 5
  finish()
}

Là, vous :

  1. Obtenez la saisie de texte – la limite de café.
  2. Enregistrez la limite dans le stockage local (en utilisant l’ID du widget).
  3. Créez un nouveau Intent pour revenir à l’appelant de l’Activité et ajoutez l’id du widget que vous configurez.
  4. Dites au système d’exploitation que la configuration est OK. Pour ce faire, passez un Intent qui contient l’id.
  5. Fermez l’écran de configuration

Attachez cet écouteur au bouton en ajoutant la ligne suivante au-dessous de setContentView() dans onCreate() :

findViewById<View>(R.id.add_button).setOnClickListener(onClickListener)

Ceci est une instruction chaînée qui trouve l’objet Button et définit son écouteur.

Lier les préférences au widget

C’est une bonne idée d’actualiser le widget après que l’utilisateur enregistre les préférences. C’est parce que la limite peut déjà être dépassée au moment de l’ajout d’un nouveau widget. Pour cette raison, écrivez une autre méthode à la fin de CoffeeLoggerWidgetConfigureActivity pour déclencher l’actualisation :

private fun updateWidget() {
  val appWidgetManager = AppWidgetManager.getInstance(this)
  CoffeeLoggerWidget.updateAppWidget(this, appWidgetManager, appWidgetId)
}

La fonction récupère le AppWidgetManager et déclenche une mise à jour du widget correspondant. Appelez cette fonction dans OnClickListener après avoir enregistré la limite de café dans coffeeLoggerPersistence. Cela devrait être le cas avant de créer l’Intent :

updateWidget()

Pour lancer l’écran de configuration à chaque fois que l’utilisateur ajoute un widget, vous devez l’ajouter au fichier de configuration du widget. En gardant cela à l’esprit, ouvrez coffee_logger_widget_info.xml et ajoutez l’attribut suivant à appwidget-provider :

android:configure="com.raywenderlich.android.coffeelogs.CoffeeLoggerWidgetConfigureActivity"

Construisez et exécutez, puis allez à l’écran d’accueil. Appuyez longuement sur le widget et faites-le glisser dans la zone « Supprimer ». Ajoutez un autre widget comme précédemment et vérifiez que l’écran de configuration apparaît. Le résultat devrait ressembler à ceci :

Entrez une valeur dans le champ, par exemple 10 et appuyez sur « Enregistrer la configuration » pour ajouter le widget.

Pour que le widget réagisse à la limite, ajoutez-le dans CoffeeLoggerWidget dans updateAppWidget*(, avant la dernière ligne :

// 1
val limit = coffeeLoggerPersistence.getLimitPref(appWidgetId)
// 2
val background = if (limit <= widgetText.toInt()) R.drawable.background_overlimit 
    else R.drawable.background
// 3
views.setInt(R.id.widget_layout, "setBackgroundResource", background)

Etape par étape :

  1. Tout d’abord, obtenez la limite enregistrée par l’utilisateur pour ce widget.
  2. Décidez si l’utilisateur dépasse la limite de café et établissez l’un des deux arrière-plans possibles : rose ou bleu.
  3. Définissez l’arrière-plan à l’élément racine du widget.

Enfin, créez et exécutez. Une fois l’application ouverte, enregistrer plus de cafés que la limite définie. Disons que votre limite était de 10 : notez trois Espresso et revenez à l’écran d’accueil. Par conséquent, votre widget est maintenant rose :

Les meilleures pratiques

Quelques conseils avant de commencer à vous aventurer dans le monde des Widgets :

  • Concevez la plus petite taille de Widget possible. Ne prenez pas la dimension réelle de l’écran si vous n’en avez pas besoin. Sachez que l’utilisateur peut le redimensionner dans une zone plus grande.
  • Ne pas actualiser le widget trop souvent car il va vider la batterie. D’un autre côté, ne le rafraîchissez pas trop rarement, car il ne sera pas utile à l’écran.
  • Assurez-vous de lire les guides officiels sur la conception de Widget et suivez les recommandations. Revisitez-les de temps en temps parce que les choses changent et que les choses sont ajoutées.
  • Considérez Widgets comme une fenêtre de raccourci dans votre application. Fournissez les informations et les actions les plus importantes.

Check Also

Comment installer le client VPN Cisco sur Windows 10 ?

Après avoir été interrompu depuis 2011, cela ne devrait pas vous déplaire que le client …