You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Glance Widget无法更新:onUpdate触发但provideGlance不执行

Android Glance Widget 更新异常排查与修复

你遇到的问题是:Glance Widget的onUpdate方法已被调用,但GlanceAppWidget的provideGlance方法并未执行,仅在应用启动或间隔一段时间后才会触发更新。提供的TodayWidgetReceiver代码如下:

class TodayWidgetReceiver : GlanceAppWidgetReceiver() {

    override val glanceAppWidget: GlanceAppWidget
        get() = TodayWidget()

    override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
        super.onUpdate(context, appWidgetManager, appWidgetIds)
        runBlocking {
            appWidgetIds.forEach {
                val glanceId = GlanceAppWidgetManager(context).getGlanceIdBy(it)
                glanceAppWidget.apply {
                    updateAppWidgetState(context, glanceId) { prefs ->
                        prefs[stringPreferencesKey("TOKEN")] = Random.nextULong().toString()
                    }
                }
                glanceAppWidget.update(context, glanceId)
            }
        }
    }

}

问题原因分析

  1. 重复更新逻辑冲突:调用super.onUpdate()会触发Glance框架默认更新流程,后续手动调用updateAppWidgetState和update会导致状态更新与UI刷新时机冲突。
  2. 主线程阻塞:runBlocking在广播接收器中使用会阻塞主线程,系统会限制广播执行时长,可能直接取消后续UI更新操作。
  3. 状态更新未正确触发渲染:手动更新状态后,可能未正确通知框架触发provideGlance重新执行。

修复方案

  1. 移除super.onUpdate()调用
    Glance框架的GlanceAppWidgetReceiver已封装默认更新逻辑,重写onUpdate后手动处理更新即可,无需调用父类方法避免冲突:

    override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
        // 移除super.onUpdate()
        CoroutineScope(Dispatchers.IO).launch {
            appWidgetIds.forEach {
                val glanceId = GlanceAppWidgetManager(context).getGlanceIdBy(it)
                glanceAppWidget.updateAppWidgetState(context, glanceId) { prefs ->
                    prefs[stringPreferencesKey("TOKEN")] = Random.nextULong().toString()
                }
                glanceAppWidget.update(context, glanceId)
            }
        }
    }
    
  2. 替换runBlocking为非阻塞协程
    使用CoroutineScope(Dispatchers.IO)执行异步操作,避免阻塞主线程,保证广播接收器能快速完成执行。

  3. 确保provideGlance依赖状态变化
    检查TodayWidget类是否在provideGlance中正确读取状态,只有状态变化时才会触发UI更新:

    class TodayWidget : GlanceAppWidget() {
        override suspend fun provideGlance(context: Context, id: GlanceId): GlanceTheme {
            val prefs = currentState(context, id)
            val token = prefs[stringPreferencesKey("TOKEN")] ?: ""
            return GlanceTheme {
                Text(text = "Token: $token")
            }
        }
    }
    
  4. 根据状态变化决定是否更新
    updateAppWidgetState会返回布尔值表示状态是否变更,可据此避免不必要的UI刷新:

    val stateChanged = glanceAppWidget.updateAppWidgetState(context, glanceId) { prefs ->
        prefs[stringPreferencesKey("TOKEN")] = Random.nextULong().toString()
    }
    if (stateChanged) {
        glanceAppWidget.update(context, glanceId)
    }
    

内容的提问来源于stack exchange,提问作者Armands L.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 14:00:02