在功能块中显示定期更新
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
创建内容会随时间推移发生变化的功能块。
使用时间轴
时间轴由一个或多个 TimelineEntry
实例组成,每个实例中包含在特定间隔时间显示的布局。所有卡片都需要时间轴。

单条目卡片
通常,可以使用单个 TimelineEntry
来描述功能块。布局是固定不变的,只有布局中的信息会发生变化。例如,显示当天健身进度的功能块会始终显示相同的进度布局,但您可以调整该布局以显示不同的值。在此类情况下,您不会事先知道内容何时会发生变化。
下面是包含单个 TimelineEntry
的功能块示例:
override fun onTileRequest(
requestParams: RequestBuilders.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(simpleLayout(this)))
.build()
return Futures.immediateFuture(tile)
}
有时限的时间轴条目
TimelineEntry
可以选择性定义一个有效期,以允许功能块在某个已知时间更改其布局,而无需应用推送新的功能块。
一个典型的例子就是日程功能块,其时间轴包含一系列即将进行的活动。每个即将进行的活动都包含一个有效期,用于指示何时显示相应活动。
Tiles API 支持有效期重叠,在这种情况下,剩余时间最短的屏幕就是当前所显示的屏幕。一次只能显示一个事件。
开发者可以提供默认后备条目。例如,日程功能块可将一个具有无限有效期的功能块作为后备,如果没有其他有效的时间轴条目,就使用该功能块,如以下代码示例所示:
override fun onTileRequest(
requestParams: RequestBuilders.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(
TimelineBuilders.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(
TimelineBuilders.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.
TimelineBuilders.TimeInterval.Builder()
.setEndMillis(meeting.dateTimeMillis)
.build()
)
.build()
)
}
val tile =
Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(timeline.build())
.build()
return Futures.immediateFuture(tile)
}
刷新功能块
功能块上显示的信息可能会在一段时间后过期。例如,天气功能块如果全天显示相同的温度并不准确。
如需处理过期数据,请在创建功能块时设置新鲜度间隔时间,用于指定功能块的有效时长。在天气功能块示例中,您可能每小时更新一次内容,如以下代码示例所示:
override fun onTileRequest(
requestParams: RequestBuilders.TileRequest
): ListenableFuture<Tile?> =
Futures.immediateFuture(
Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setFreshnessIntervalMillis(60 * 60 * 1000) // 60 minutes
.setTileTimeline(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 秒的定时器。
- 如果您在时间耗尽之前从远程数据源收到更新,则显示数据同步中已更新的值。否则,显示已缓存的本地值。
为您推荐
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-09-11。
[null,null,["最后更新时间 (UTC):2025-09-11。"],[],[],null,["Create tiles with content that changes as time passes.\n\nWork with timelines\n\nA timeline consists of one or more\n[`TimelineEntry`](/reference/androidx/wear/protolayout/TimelineBuilders.TimelineEntry)\ninstances, each of which contain a layout that is displayed during a specific\ntime interval. All tiles need a timeline.\n\nSingle-entry tiles\n\nOften a tile can be described with a single `TimelineEntry`. The layout is\nfixed, and only the information inside the layout changes. For example, a tile\nthat shows your fitness progress of the day always shows the same progress\nlayout, though you might adjust that layout to show different values. In these\ncases, you don't know in advance when the content might change.\n\nSee the following example of a tile with a single `TimelineEntry`: \n\n```kotlin\noverride fun onTileRequest(\n requestParams: RequestBuilders.TileRequest\n): ListenableFuture\u003cTile?\u003e {\n val tile =\n Tile.Builder()\n .setResourcesVersion(RESOURCES_VERSION)\n // We add a single timeline entry when our layout is fixed, and\n // we don't know in advance when its contents might change.\n .setTileTimeline(Timeline.fromLayoutElement(simpleLayout(this)))\n .build()\n return Futures.immediateFuture(tile)\n}https://github.com/android/snippets/blob/292ef1d272c0bc68a2d226871394065a97b06795/wear/src/main/java/com/example/wear/snippets/tile/Tile.kt#L81-L92\n```\n\nTimebound timeline entries\n\nA `TimelineEntry` can optionally define a validity period, allowing a tile to\nchange its layout at a known time without requiring the app to push a new tile.\n\nThe canonical example is an agenda tile whose timeline contains a list of\nupcoming events. Each upcoming event contains a validity period to indicate when\nto show it.\n\nThe tiles API allows for overlapping validity periods, where the screen with the\nshortest period of time left is the one shown. Only one event is displayed at a\ntime.\n\nDevelopers can provide a default fallback entry. For example, the agenda tile\ncould have a tile with an infinite validity period, which is used if no other\ntimeline entry is valid, as shown in the following code sample: \n\n```kotlin\noverride fun onTileRequest(\n requestParams: RequestBuilders.TileRequest\n): ListenableFuture\u003cTile?\u003e {\n val timeline = Timeline.Builder()\n\n // Add fallback \"no meetings\" entry\n // Use the version of TimelineEntry that's in androidx.wear.protolayout.\n timeline.addTimelineEntry(\n TimelineBuilders.TimelineEntry.Builder().setLayout(getNoMeetingsLayout()).build()\n )\n\n // Retrieve a list of scheduled meetings\n val meetings = MeetingsRepo.getMeetings()\n // Add a timeline entry for each meeting\n meetings.forEach { meeting -\u003e\n timeline.addTimelineEntry(\n TimelineBuilders.TimelineEntry.Builder()\n .setLayout(getMeetingLayout(meeting))\n .setValidity(\n // The tile should disappear when the meeting begins\n // Use the version of TimeInterval that's in\n // androidx.wear.protolayout.\n TimelineBuilders.TimeInterval.Builder()\n .setEndMillis(meeting.dateTimeMillis)\n .build()\n )\n .build()\n )\n }\n\n val tile =\n Tile.Builder()\n .setResourcesVersion(RESOURCES_VERSION)\n .setTileTimeline(timeline.build())\n .build()\n return Futures.immediateFuture(tile)\n}https://github.com/android/snippets/blob/292ef1d272c0bc68a2d226871394065a97b06795/wear/src/main/java/com/example/wear/snippets/tile/Tile.kt#L125-L161\n```\n\nRefresh a tile\n\nInformation shown on a tile might expire after some time. For example, a weather\ntile that shows the same temperature throughout the day isn't accurate.\n\nTo deal with expiring data, set a freshness interval at the time of creating a\ntile, which specifies how long the tile is valid. In the example of the weather\ntile, you might update its content every hour, as shown in the following code\nsample: \n\n```kotlin\noverride fun onTileRequest(\n requestParams: RequestBuilders.TileRequest\n): ListenableFuture\u003cTile?\u003e =\n Futures.immediateFuture(\n Tile.Builder()\n .setResourcesVersion(RESOURCES_VERSION)\n .setFreshnessIntervalMillis(60 * 60 * 1000) // 60 minutes\n .setTileTimeline(Timeline.fromLayoutElement(getWeatherLayout()))\n .build()\n )https://github.com/android/snippets/blob/292ef1d272c0bc68a2d226871394065a97b06795/wear/src/main/java/com/example/wear/snippets/tile/Tile.kt#L169-L178\n```\n\nWhen you set a freshness interval, the system calls\n[`onTileRequest()`](/reference/androidx/wear/tiles/TileService#onTileRequest(androidx.wear.tiles.RequestBuilders.TileRequest))\nshortly after the interval finishes. If you don't set a freshness interval, the\nsystem doesn't call `onTileRequest()`.\n\nA tile can also expire because of an external event. For example, a user might\nremove a meeting from their calendar, and if the tile wasn't refreshed, then the\ntile would still show that deleted meeting. In this case, request a refresh from\nany place in your application code, as shown in the following code sample: \n\nKotlin \n\n```kotlin\nfun eventDeletedCallback() {\n TileService.getUpdater(context)\n .requestUpdate(MyTileService::class.java)\n}\n```\n\nJava \n\n```java\npublic void eventDeletedCallback() {\n TileService.getUpdater(context)\n .requestUpdate(MyTileService.class);\n}\n```\n\nChoose an update workflow\n\nUse these best practices to determine how to configure your tile updates:\n\n- If the update is predictable---for example, if it's for the next event in the user's calendar---use a timeline.\n- When you fetch platform data, use data binding so that the system updates the data automatically.\n- If the update can be calculated on-device in a small amount of time---such\n as updating the position of an image on a sunrise tile---use\n [`onTileRequest()`](/reference/androidx/wear/tiles/TileService#onTileRequest(androidx.wear.tiles.RequestBuilders.TileRequest)).\n\n This is particularly useful when you need to generate all images ahead of\n time. If you need to generate a new image at a future time, call\n [`setFreshnessIntervalMillis()`](/reference/androidx/wear/tiles/TileBuilders.Tile.Builder#setFreshnessIntervalMillis(long)).\n- If you're doing more intensive background work repeatedly, such as polling\n for weather data, use [`WorkManager`](/topic/libraries/architecture/workmanager), and push updates to your tile.\n\n- If the update is in response to an external event---such as the lights\n turning on, receiving an email, or updating a note---send a [Firebase Cloud\n Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging) message to make your app active again, then push updates\n to the tile.\n\n- If the tile data sync process might be expensive, do the following:\n\n 1. Schedule a data sync.\n 2. Start a timer for 1-2 seconds.\n 3. If you receive an update from a remote data source before time runs out, show the updated value from the data sync. Otherwise, show a cached local value.\n\nRecommended for you\n\n- Note: link text is displayed when JavaScript is off\n- [Minimize the effect of regular updates](/develop/connectivity/minimize-effect-regular-updates)\n- [Access location in the background](/develop/sensors-and-location/location/background)\n- [Getting started with WorkManager](/develop/background-work/background-tasks/persistent/getting-started)"]]