创建内容会随时间推移发生变化的功能块。
使用时间轴
时间轴由一个或多个 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
可以选择性定义一个有效期,以允许功能块在某个已知时间更改其布局,而无需应用推送新的功能块。
一个典型的例子就是日程功能块,其时间轴包含一系列即将进行的活动。每个即将进行的活动都包含一个有效期,用于指示何时显示相应活动。
Tiles 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 秒的定时器。
- 如果您在时间耗尽之前从远程数据源收到更新,则显示数据同步中已更新的值。否则,显示已缓存的本地值。
为您推荐
- 注意:当 JavaScript 处于关闭状态时,系统会显示链接文字
- 尽量减少定期更新的影响
- 在后台访问位置信息
- WorkManager 使用入门