在資訊方塊內顯示定期更新內容

建立可隨著時間變更內容的資訊方塊。

使用時間軸

時間軸含有一或多個 TimelineEntry 例項,每個例項各有一個會在特定時間間隔顯示的版面配置。所有資訊方塊都需要時間軸。

資訊方塊時間軸圖表

單一項目資訊方塊

資訊方塊通常可以用單一 TimelineEntry 說明。版面配置是固定的,只有版面配置中的資訊會變更。舉例來說,顯示當日健身進度的資訊方塊一律會顯示相同的進度版面配置,不過您可能會為了顯示不同的值而調整版面配置。在這種情況下,您無法事先得知內容何時會變更。

請參考以下設有單一 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);
}

設有時間限制的時間軸項目

您可以選擇使用 TimelineEntry 定義有效期間,資訊方塊就能在已知時間變更版面配置,不必要求應用程式推送新的資訊方塊。

此做法的經典示例,就是時間軸含有近期活動清單的議程資訊方塊。每個近期活動都設定了有效期間,指出顯示活動的時間。

資訊方塊 API 允許有效期間重疊。在這種情況下,系統會顯示剩餘期間最短的畫面。系統一次只會顯示一個事件。

開發人員可以提供預設的備用項目。舉例來說,議程資訊方塊可提供有效期間為無限期的資訊方塊,並用於沒有其他有效時間軸項目的情況,如以下程式碼範例所示:

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

重新整理資訊方塊

資訊方塊顯示的資訊可能會在一段時間後失效。舉例來說,如果天氣資訊方塊整天都顯示相同溫度,就會不準確。

為處理失效的資料,請在建立資訊方塊時設定更新間隔,指定資訊方塊的有效時間長度。以天氣資訊方塊為例,您可以每小時更新一次內容,如下列程式碼範例所示:

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

設定更新間隔後,系統會在間隔結束後隨即呼叫 onTileRequest()。如果未設定更新間隔,系統就不會呼叫 onTileRequest()

資訊方塊也可能因外部事件而失效。例如使用者可能會從行事曆移除會議,如果資訊方塊並未重新整理,就仍會顯示已刪除的會議。在這種情況下,請在應用程式程式碼中的任意位置要求重新整理,如以下程式碼範例所示:

Kotlin

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

Java

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

選擇更新工作流程

運用下列最佳做法,決定如何設定資訊方塊更新:

  • 如果是可預測的更新內容 (例如使用者日曆中的下一個活動),請使用時間軸。
  • 擷取平台資料時,請使用資料繫結,讓系統自動更新資料。
  • 如果能在短時間內於裝置端計算出更新內容 (例如在日出資訊方塊中更新圖片的位置),請使用 onTileRequest()

    當您需要提早產生所有圖片時,這種做法特別實用。如果需要在未來產生新圖片,請呼叫 setFreshnessIntervalMillis()

  • 如果會重複執行大量背景工作 (例如輪詢天氣資料),請使用 WorkManager,並將更新內容推送至資訊方塊。

  • 如果是回應外部事件 (例如開燈、接收電子郵件或更新記事) 的更新內容,請傳送 Firebase 雲端通訊 (FCM) 訊息再次啟動應用程式,然後將更新內容推送至資訊方塊。

  • 如果資訊方塊資料同步程序可能會耗用大量資源,請執行以下操作:

    1. 排定資料同步處理作業。
    2. 啟動 1 到 2 秒的計時器。
    3. 如果在時間結束前收到遠端資料來源提供的更新內容,透過資料同步作業顯示更新後的值。否則,顯示快取的本機值。