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

Android App Widget二次亮屏后倒计时UI不更新问题求助

Hey there! Let's dig into why your currency exchange widget's countdown UI gets stuck after two screen off/on cycles—even though you've confirmed the timer is running and updateAppWidget is triggered.

What's Likely Causing the Issue

The core problem is almost certainly related to reusing the same RemoteViews instance across updates. RemoteViews is a cross-process object, and reusing it can lead to stale state being cached by the system. Even if you update the text in the old RemoteViews instance, the widget host might not recognize the change as a meaningful update, especially after multiple screen state transitions.

Additionally, relying solely on the onTick callback to update the UI when the screen is on can lead to delays or missed refreshes if the system batches widget updates during screen transitions.

Fixes to Implement

Here are actionable steps to resolve the stuck UI:

  1. Use a fresh RemoteViews instance every time you update
    Instead of reusing a single RemoteViews object, create a new one in each onTick call. This ensures the system picks up the UI change immediately.

  2. Listen for screen-on broadcasts to force an immediate refresh
    Register a broadcast receiver to catch the ACTION_SCREEN_ON event, then trigger a widget update right when the screen turns on. This eliminates any waiting for the next onTick cycle.

  3. Double-check screen state detection for cross-version compatibility
    Ensure your PowerManager logic works reliably across all Android versions you support.

Modified Code Example

First, add a broadcast receiver to handle screen-on events:

class ScreenOnReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (intent.action == Intent.ACTION_SCREEN_ON) {
            // Trigger widget update immediately
            val appWidgetManager = AppWidgetManager.getInstance(context)
            val componentName = ComponentName(context, YourWidgetProvider::class.java)
            val appWidgetIds = appWidgetManager.getAppWidgetIds(componentName)
            // Call your existing update method
            YourWidgetProvider.updateAllWidgets(context, appWidgetManager, appWidgetIds)
        }
    }
}

Register/unregister the receiver in your widget provider:

override fun onEnabled(context: Context) {
    super.onEnabled(context)
    val filter = IntentFilter(Intent.ACTION_SCREEN_ON)
    context.registerReceiver(ScreenOnReceiver(), filter)
}

override fun onDisabled(context: Context) {
    super.onDisabled(context)
    context.unregisterReceiver(ScreenOnReceiver())
}

Update your countdown logic to use fresh RemoteViews:

if (timestamp.isNotEmpty()) {
    countDownTimer?.cancel()
    countDownTimer = null

    val difference = DateUtils.getDifference(timestamp)
    countDownTimer = object : CountDownTimer(difference, 1000) {
        override fun onFinish() {
            viewModel.getPrice()
            // Update widget when countdown finishes
            val finishViews = RemoteViews(context.packageName, com.example.bipexchange.R.layout.your_widget_layout)
            finishViews.setTextViewText(com.example.bipexchange.R.id.countDownTV, context.getString(R.string.countdown_complete))
            appWidgetManager.updateAppWidget(appWidgetId, finishViews)
        }

        override fun onTick(millisUntilFinished: Long) {
            val (minutesLeft, secsLeft) = DateUtils.getMinAndSecsLeft(millisUntilFinished)
            
            // Create a fresh RemoteViews instance every tick
            val freshViews = RemoteViews(context.packageName, com.example.bipexchange.R.layout.your_widget_layout)
            freshViews.setTextViewText(
                com.example.bipexchange.R.id.countDownTV,
                context.getString(
                    com.example.bipexchange.R.string.minutesSeconds,
                    minutesLeft,
                    secsLeft
                )
            )

            val pm = getSystemService(context, PowerManager::class.java)
            val isScreenOn = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
                pm?.isInteractive
            } else {
                pm?.isScreenOn
            }

            if (isScreenOn == true) {
                appWidgetManager.updateAppWidget(appWidgetId, freshViews)
            }
        }
    }
    countDownTimer?.start()
}

Why This Works

  • Fresh RemoteViews: Each update uses a new instance, so the system can't ignore the change due to cached state.
  • Screen-on broadcast: Ensures the widget refreshes instantly when the screen turns on, syncing the UI with the current timer state immediately.
  • Robust screen detection: The version-specific PowerManager check ensures you're correctly identifying when the screen is active across all supported devices.

内容的提问来源于stack exchange,提问作者Wolf Gate

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:47:13