管理和更新 GlanceAppWidget

以下部分介绍了如何更新 GlanceAppWidget 并管理其状态。

管理 GlanceAppWidget 状态

每当创建 widget 或需要更新 widget 时,系统都会实例化所提供的 GlanceAppWidget 类,因此该类应为无状态且被动

状态的概念可分为以下几类:

  • 应用状态:widget 所需的应用状态或内容。例如,用户定义的已存储目的地列表(即数据库)。
  • 概览状态:仅与应用 widget 相关且不一定会修改或影响应用状态的特定状态。例如,在 widget 中选中了一个复选框或增加了计数器。

使用应用状态

应用 widget 应该是被动的。每个应用都负责管理数据层并处理状态(例如反映在 widget 界面中的空闲、加载和错误状态)。

例如,以下代码从代码库层的内存缓存中检索目的地,提供存储的目的地列表,并根据其状态显示不同的界面:

class DestinationAppWidget : GlanceAppWidget() {

    // ...

    @Composable
    fun MyContent() {
        val repository = remember { DestinationsRepository.getInstance() }
        // Retrieve the cache data everytime the content is refreshed
        val destinations by repository.destinations.collectAsState(State.Loading)

        when (destinations) {
            is State.Loading -> {
                // show loading content
            }

            is State.Error -> {
                // show widget error content
            }

            is State.Completed -> {
                // show the list of destinations
            }
        }
    }
}

每当状态或数据发生变化时,应用都有责任通知并更新 widget。如需了解详情,请参阅更新 GlanceAppWidget

更新GlanceAppWidget

您可以使用 GlanceAppWidget 请求更新 widget 内容。如管理 GlanceAppWidget 状态部分中所述,应用 widget 托管在不同的进程中。Glance 将内容转换为实际的 RemoteViews 并将其发送到宿主。如需更新内容,Glance 必须重新创建 RemoteViews 并再次发送。

如需发送更新,请调用 GlanceAppWidget 实例的 update 方法,并提供 contextglanceId

MyAppWidget().update(context, glanceId)

如需获取 glanceId,请查询 GlanceAppWidgetManager

val manager = GlanceAppWidgetManager(context)
val widget = GlanceSizeModeWidget()
val glanceIds = manager.getGlanceIds(widget.javaClass)
glanceIds.forEach { glanceId ->
    widget.update(context, glanceId)
}

或者,使用以下某个 GlanceAppWidget update 扩展程序:

// Updates all placed instances of MyAppWidget
MyAppWidget().updateAll(context)

// Iterate over all placed instances of MyAppWidget and update if the state of
// the instance matches the given predicate
MyAppWidget().updateIf<State>(context) { state ->
    state == State.Completed
}

这些方法可从应用的任何部分调用。由于它们是 suspend 函数,我们建议在主线程范围之外启动它们。在以下示例中,它们是在 CoroutineWorker 中启动的:

class DataSyncWorker(
    val context: Context,
    val params: WorkerParameters,
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        // Fetch data or do some work and then update all instance of your widget
        MyAppWidget().updateAll(context)
        return Result.success()
    }
}

如需详细了解协程,请参阅 Android 上的 Kotlin 协程

何时更新 widget

立即或定期更新 widget。

当应用处于唤醒状态时,widget 可以立即更新。例如:

  • 当用户与 widget 互动时,会触发操作、lambda 调用或启动 activity 的 intent。
  • 当用户在前台与应用互动时,或者当应用已在响应 Firebase Cloud Messaging (FCM) 消息或广播时更新。

在这些情况下,请按照本指南中的说明调用 update 方法。

即使应用未唤醒,widget 也可以定期更新。例如:

  • 使用 updatePeriodMillis 最多每 30 分钟更新一次 widget。
  • 使用 WorkManager 可安排更频繁的更新,例如每 15 分钟更新一次。
  • 更新 widget 以响应广播。

资源