Afficher des informations périodiques dans des cartes

Créez des cartes dont le contenu change au fil du temps.

Utiliser les chronologies

Une chronologie se compose d'une ou plusieurs instances TimelineEntry, chacune contenant une mise en page qui s'affiche pendant un intervalle de temps spécifique. Toutes les cartes ont besoin d'une chronologie.

Diagramme de la chronologie des cartes

Cartes à entrée unique

Une carte peut souvent être décrite à l'aide d'une seule TimelineEntry. La mise en page est fixe et seules les informations qu'elle contient changent. Par exemple, une carte indiquant vos progrès fitness quotidiens affiche toujours la même mise en page de progression, mais vous pouvez ajuster cette mise en page pour afficher des valeurs différentes. Dans ces cas, il est impossible de savoir à l'avance quand le contenu est susceptible de changer.

Consultez l'exemple suivant d'une carte avec une seule TimelineEntry :

Kotlin

override fun onTileRequest(
    requestParams: TileRequest
): ListenableFuture<Tile> {
    val tile = Tile.Builder()
        .setResourcesVersion(RESOURCES_VERSION)

        // We add a single timeline entry when our layout is fixed, and
        // we don't know in advance when its contents might change.
        .setTileTimeline(
            Timeline.fromLayoutElement(...)
        ).build()
    return Futures.immediateFuture(tile)
}

Java

@Override
protected ListenableFuture<Tile> onTileRequest(
       @NonNull TileRequest requestParams
) {
   Tile tile = new Tile.Builder()
       .setResourcesVersion(RESOURCES_VERSION)
       
       // We add a single timeline entry when our layout is fixed, and
       // we don't know in advance when its contents might change.
       .setTileTimeline(
            Timeline.fromLayoutElement(...)
       ).build();
   return Futures.immediateFuture(tile);
}

Entrées de chronologie limitées dans le temps

Une TimelineEntry peut éventuellement définir une période de validité, permettant à une carte de modifier sa mise en page à un moment défini sans que l'application transmette une nouvelle carte.

L'exemple canonique est une carte de planning dont la chronologie contient une liste d'événements à venir. Chaque événement à venir contient une période de validité indiquant à quel moment il doit être affiché.

L'API des cartes permet le chevauchement des périodes de validité, où l'écran dont la durée restante est la plus courte est celui qui est affiché. Un seul événement est affiché à la fois.

Les développeurs peuvent fournir une entrée de remplacement par défaut. Par exemple, la carte de planning peut disposer d'une carte avec une période de validité infinie, utilisée si aucune autre entrée de chronologie n'est valide, comme illustré dans l'exemple de code suivant :

Kotlin

public override fun onTileRequest(
    requestParams: TileRequest
): ListenableFuture<Tile> {
    val timeline = Timeline.Builder()

    // Add fallback "no meetings" entry
    // Use the version of TimelineEntry that's in androidx.wear.protolayout.
    timeline.addTimelineEntry(TimelineEntry.Builder()
        .setLayout(getNoMeetingsLayout())
        .build()
    )

    // Retrieve a list of scheduled meetings
    val meetings = MeetingsRepo.getMeetings()
    // Add a timeline entry for each meeting
    meetings.forEach { meeting ->
        timeline.addTimelineEntry(TimelineEntry.Builder()
            .setLayout(getMeetingLayout(meeting))
            .setValidity(
                // The tile should disappear when the meeting begins
                // Use the version of TimeInterval that's in
                // androidx.wear.protolayout.
                TimeInterval.Builder()
                    .setEndMillis(meeting.dateTimeMillis).build()
            ).build()
        )
    }

    val tile = Tile.Builder()
        .setResourcesVersion(RESOURCES_VERSION)
        .setTileTimeline(timeline.build())
        .build()
    return Futures.immediateFuture(tile)
}

Java

@Override
protected ListenableFuture<Tile> onTileRequest(
       @NonNull RequestBuilders.TileRequest requestParams
) {
   Timeline.Builder timeline = new Timeline.Builder();
   // Add fallback "no meetings" entry
   // Use the version of TimelineEntry that's in androidx.wear.protolayout.
   timeline.addTimelineEntry(new TimelineEntry.Builder().setLayout(getNoMeetingsLayout()).build());
   // Retrieve a list of scheduled meetings
   List<Meeting> meetings = MeetingsRepo.getMeetings();
   // Add a timeline entry for each meeting
   for(Meeting meeting : meetings) {
        timeline.addTimelineEntry(new TimelineEntry.Builder()
            .setLayout(getMeetingLayout(meeting))
            .setValidity(
                // The tile should disappear when the meeting begins
                // Use the version of TimeInterval that's in
                // androidx.wear.protolayout.
                new TimeInterval.builder()
                    .setEndMillis(meeting.getDateTimeMillis()).build()
            ).build()
        );
    }

    Tile tile = new Tile.Builder()
        .setResourcesVersion(RESOURCES_VERSION)
        .setTileTimeline(timeline.build())
        .build();
    return Futures.immediateFuture(tile);
}

Actualiser une carte

Les informations affichées sur une carte peuvent expirer au bout d'un certain temps. Par exemple, une carte météo qui affiche la même température tout au long de la journée n'est pas précise.

Pour traiter les données arrivant à expiration, définissez un intervalle d'actualisation lors de la création d'une carte, qui spécifie la durée de validité de la carte. Dans l'exemple de carte météo, vous pouvez actualiser le contenu une fois par heure, comme illustré dans l'exemple de code suivant :

Kotlin

override fun onTileRequest(requestParams: RequestBuilders.TileRequest) =
    Futures.immediateFuture(Tile.Builder()
        .setResourcesVersion(RESOURCES_VERSION)
        .setFreshnessIntervalMillis(60 * 60 * 1000) // 60 minutes
        .setTileTimeline(Timeline.fromLayoutElement(
            getWeatherLayout())
        ).build()
    )

Java

@Override
protected ListenableFuture<Tile> onTileRequest(
       @NonNull TileRequest requestParams
) {
    return Futures.immediateFuture(new Tile.Builder()
        .setResourcesVersion(RESOURCES_VERSION)
        .setFreshnessIntervalMillis(60 * 60 * 1000) // 60 minutes
        .setTimeline(Timeline.fromLayoutElement(
            getWeatherLayout())
        ).build());
}

Lorsque vous définissez un intervalle d'actualisation, le système appelle onTileRequest() peu après la fin de l'intervalle. Si vous ne définissez pas d'intervalle d'actualisation, le système n'appelle pas onTileRequest().

Une carte peut également expirer en raison d'un événement externe. Par exemple, un utilisateur peut supprimer une réunion de son agenda. Si la carte n'a pas été actualisée, elle affiche quand même la réunion supprimée. Dans ce cas, demandez une actualisation depuis n'importe quel emplacement du code de votre application, comme indiqué dans l'exemple de code suivant :

Kotlin

fun eventDeletedCallback() {
     TileService.getUpdater(context)
             .requestUpdate(MyTileService::class.java)
}

Java

public void eventDeletedCallback() {
   TileService.getUpdater(context)
           .requestUpdate(MyTileService.class);
}

Choisir un workflow de mise à jour

Suivez ces bonnes pratiques pour déterminer comment configurer les mises à jour de vos cartes :

  • Si la mise à jour est prévisible (par exemple, si elle concerne le prochain événement dans l'agenda de l'utilisateur), utilisez une chronologie.
  • Lorsque vous extrayez des données de plate-forme, utilisez la liaison de données afin que le système mette automatiquement à jour les données.
  • Si la mise à jour peut être calculée sur l'appareil en un court laps de temps, par exemple pour mettre à jour la position d'une image sur une carte de lever du soleil, utilisez onTileRequest().

    Cela est particulièrement utile lorsque vous devez générer toutes les images à l'avance. Si vous devez générer une nouvelle image ultérieurement, appelez setFreshnessIntervalMillis().

  • Si vous effectuez des tâches plus intensives en arrière-plan, par exemple si vous récupérez des données météorologiques, utilisez WorkManager et déployez les mises à jour de votre carte.

  • Si la mise à jour intervient en réponse à un événement externe, tel que l'allumage des lumières, la réception d'un e-mail ou la mise à jour d'une note, envoyez un message Firebase Cloud Messaging (FCM) pour réactiver votre application, puis envoyez les mises à jour à la carte.

  • Si le processus de synchronisation des données des cartes peut être coûteux, procédez comme suit :

    1. Planifiez une synchronisation des données.
    2. Démarrez un minuteur de 1 à 2 secondes.
    3. Si vous recevez une mise à jour d'une source de données distante avant l'expiration du délai, affichez la valeur mise à jour lors de la synchronisation des données. Sinon, affichez une valeur locale mise en cache.