在 Android 中,Glance 小部件在每次更新期间都会“闪烁”(即使没有内容更改)

use*_*854 4 android glance glance-appwidget

我不确定这是否是 Glance 仍处于 alpha 版本时出现的问题,或者我是否做错了什么。但每次onUpdate()触发小部件接收器时,它都会被完全重新组合。它重置为initialLayout一秒钟,然后重新组合到正确的状态。

问题是,即使小部件状态没有变化,它也会发生,所以每次小部件更新时它都会像这样“闪烁”,看起来非常糟糕。

我已经使用 实现了手动更新MyWidget().updateIf<Preferences>,以便我的应用程序仅在状态更改时更新小部件,但操作系统仍在执行自动更新,因此“闪烁”仍在发生。

编辑: 经过更多测试,我发现调用该GlanceAppWidget update()方法时实际上并没有发生这种情况。事实上,我删除了对我的应用程序的所有GlanceAppWidget调用GlanceAppWidgetManager。但是,每当小部件更新(由操作系统自动触发)时,“闪烁”仍然会发生。

我尝试通过将 设为 0 和 86400000 来禁用 XML 中的小部件刷新updatePeriodMillis但这似乎不起作用updatePeriodMillis我也尝试过从 XML 中删除。

因此,似乎只要 GlanceAppWidget 调用其 Content() 函数,就会发生闪烁,无论实际触发该调用的是什么。仅供参考,下面是该小部件的基本 Kotlin 类:

class WidgetSimple : GlanceAppWidget() {

    override val sizeMode: SizeMode = SizeMode.Single

    @Composable
    override fun Content() {

        // code to actually draw the components
        // no matter what's here, the widget will flicker
        // even if we leave it blank, it'll still flicker between the preview layout and a blank screen
    }
}

class WidgetSimpleReceiver : GlanceAppWidgetReceiver() {
    override val glanceAppWidget: GlanceAppWidget = WidgetSimple()
}
Run Code Online (Sandbox Code Playgroud)

use*_*854 6

在 Google 的问题跟踪器上发布错误并进行大量故障排除以找出发生的情况后,我发现这是 WorkManager 的问题,而不是 Glance 或其他任何与小部件相关的问题。由于 WorkManager 的行为方式,简单地将任何工作放入队列都会导致小部件闪烁。

但是,该 Issue Tracker 线程中提供了一种解决方案,即创建一个设置为 10 年后的一次性 Worker(使用setInitialDelay)并对其设置至少一个约束。

这可确保 WorkManager 组件不会被禁用,并且应用程序小部件更新不会无意中触发。您可以使用它 ExistingWorkPolicy.KEEP来确保后续的无操作入队

基本上,我必须创建一个虚拟 CoroutineWorker 类,它实际上在 doWork() 内不执行任何操作:

class DelayedWidgetWorker(
    appContext: Context,
    workerParams: WorkerParameters,
): CoroutineWorkerCompat(appContext, workerParams) {

    companion object{
        const val TAG = "appWidgetWorkerKeepEnabled"
    }

    override suspend fun doWork(): Result {
        Logger.d("Dummy DelayedWidgetWorker")
        return Result.success()
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在每次小部件更新之前调用此函数:

        WorkManager.getInstance(context).enqueueUniqueWork(
            DelayedWidgetWorker.TAG,
            ExistingWorkPolicy.KEEP,
            OneTimeWorkRequestBuilder<DelayedWidgetWorker>()
                .setInitialDelay(10 * 365, TimeUnit.DAYS)
                .setConstraints(
                    Constraints.Builder()
                        .setRequiresCharging(true)
                        .build()
                )
                .build()
        )
Run Code Online (Sandbox Code Playgroud)

这可以确保 10 年后队列中始终有一个 WorkManager 任务,从而防止它导致“闪烁”