在磁贴中显示定期更新

创建包含随时间推移而变化的内容的磁贴。

使用时间线

时间线包含一个或多个 TimelineEntry 实例,每个实例包含在特定时间间隔内显示的布局。所有磁贴都需要时间线。

Diagram of tile timeline

单条目磁贴

磁贴通常可以用单个 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 Cloud Messaging (FCM) 消息以使您的应用程序再次处于活动状态,然后将更新推送到瓷砖。

  • 如果瓷砖数据同步过程可能很昂贵,请执行以下操作

    1. 安排数据同步。
    2. 启动一个持续 1-2 秒的计时器。
    3. 如果您在计时器超时前从远程数据源收到更新,请显示来自数据同步的更新值。否则,显示缓存的本地值。