Pokazuj okresowe aktualizacje w kafelkach

Twórz kafelki z treścią, która zmienia się wraz z upływem czasu.

Praca z oś czasu

Oś czasu składa się z 1 lub kilku wystąpień TimelineEntry, z których każda zawiera układ wyświetlany w określonym przedziale czasu. Wszystkie kafelki wymagają osi czasu.

Schemat osi czasu kafelków

Kafelki z jednym wejściem

Często kafelek można opisać za pomocą pojedynczego elementu TimelineEntry. Układ jest stały i zmieniają się tylko informacje w nim. Na przykład kafelek z postępami w aktywności fizycznej w danym dniu zawsze pokazuje taki sam układ postępu, ale można go dostosować, by pokazywał inne wartości. W takich przypadkach nie wiadomo z wyprzedzeniem, kiedy treść może ulec zmianie.

Oto przykład kafelka z 1 elementem 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);
}

Wpisy na osi czasu związane z czasem

TimelineEntry może opcjonalnie definiować okres ważności, co umożliwia kafelkowi zmianę jego układu w znanym czasie bez konieczności wprowadzania nowego kafelka.

Przykładem strony kanonicznej jest kafelek planu dnia, którego oś czasu zawiera listę nadchodzących wydarzeń. Każde nadchodzące wydarzenie zawiera okres ważności, który wskazuje, kiedy ma się wyświetlać.

Interfejs tiles API umożliwia stosowanie pokrywających się okresów ważności. W tym przypadku wyświetlany jest ekran z najkrótszym czasem do końca. Wyświetlane jest tylko jedno zdarzenie naraz.

Deweloperzy mogą udostępniać domyślny wpis zastępczy. Na przykład kafelek planu dnia może zawierać kafelek z nieskończonym okresem ważności. Jest on używany wtedy, gdy nie jest prawidłowy żaden inny wpis na osi czasu, jak widać w tym przykładowym kodzie:

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);
}

Odświeżanie kafelka

Informacje wyświetlone na kafelku mogą wygasnąć po pewnym czasie. Na przykład kafelek pogodowy, który pokazuje tę samą temperaturę przez cały dzień, jest niedokładny.

Aby radzić sobie z wygasającymi danymi, podczas tworzenia kafelka ustaw przedział aktualności, który określa, jak długo jest on ważny. Na przykładzie kafelka z pogodą możesz aktualizować jego zawartość co godzinę, jak w tym przykładzie kodu:

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());
}

Gdy ustawisz przedział czasu aktualności, system wywoła metodę onTileRequest() krótko po jego zakończeniu. Jeśli nie ustawisz interwału aktualności, system nie wywoła funkcji onTileRequest().

Kafelek może też wygasnąć w wyniku zdarzenia zewnętrznego. Użytkownik może na przykład usunąć spotkanie ze swojego kalendarza, a jeśli kafelek nie zostanie odświeżony, kafelek nadal będzie zawierał usunięte spotkanie. W takim przypadku poproś o odświeżenie z dowolnego miejsca w kodzie aplikacji, jak pokazano w tym przykładowym kodzie:

Kotlin

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

Java

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

Wybierz przepływ pracy aktualizacji

Aby określić, jak skonfigurować aktualizacje kafelków, skorzystaj z tych sprawdzonych metod:

  • Jeśli aktualizacja jest przewidywalna – na przykład dotyczy następnego wydarzenia w kalendarzu użytkownika – użyj osi czasu.
  • Gdy pobierasz dane z platformy, użyj powiązania danych, aby system automatycznie je aktualizował.
  • Jeśli aktualizację można obliczyć na urządzeniu w krótkim czasie – na przykład przez zmianę pozycji obrazu na kafelku wschodu słońca – użyj onTileRequest().

    Jest to szczególnie przydatne, gdy musisz wygenerować wszystkie obrazy z wyprzedzeniem. Jeśli w przyszłości musisz wygenerować nowy obraz, wywołaj metodę setFreshnessIntervalMillis().

  • Jeśli wielokrotnie wykonujesz bardziej intensywną pracę w tle, na przykład przeprowadzasz odpytywanie danych pogodowych, użyj WorkManager i przesyłaj aktualizacje do kafelka.

  • Jeśli aktualizacja jest reakcją na zdarzenie zewnętrzne – takie jak zapalenie światła, otrzymanie e-maila lub zaktualizowanie notatki – wyślij wiadomość w chmurze Firebase (FCM), aby ponownie aktywować aplikację, a następnie prześlij aktualizacje do kafelka.

  • Jeśli proces synchronizacji danych kafelków może być kosztowny, wykonaj te czynności:

    1. Zaplanuj synchronizację danych.
    2. Włącz minutnik na 1–2 sekundy.
    3. Jeśli otrzymasz aktualizację ze zdalnego źródła danych przed upływem limitu czasu, wyświetl zaktualizowaną wartość z synchronizacji danych. W przeciwnym razie pokaż wartość lokalną z pamięci podręcznej.