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

如何实现基于Glance的Jetpack Compose Widget每分钟定时更新

实现Glance Widget每分钟更新的方案

由于Android系统对App Widget的官方更新机制有严格频率限制(updatePeriodMillis最小30分钟,WorkManager周期性任务最小15分钟),要实现每分钟更新,需要绕过系统自动更新逻辑,采用主动触发Widget刷新的方式。以下是两种可行方案:

方案一:前台服务 + 定时任务

前台服务可避免被系统后台杀死,结合协程或Handler实现稳定的分钟级定时更新。

实现步骤

  1. 添加权限声明
    在AndroidManifest.xml中声明所需权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- Android 13+ 必需 -->
  1. 创建前台更新服务
    服务内部通过协程循环触发Widget更新:
class WidgetUpdateService : Service() {
    private val job = Job()
    private val scope = CoroutineScope(Dispatchers.IO + job)

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // 启动前台通知(Android 8.0+ 强制要求)
        val notification = NotificationCompat.Builder(this, "WIDGET_UPDATE_CHANNEL")
            .setContentTitle("Widget更新服务")
            .setContentText("保持Widget实时更新")
            .setSmallIcon(R.drawable.ic_notification)
            .build()
        startForeground(1, notification)

        // 每分钟执行一次Widget更新
        scope.launch {
            while (isActive) {
                GlanceAppWidgetManager(this@WidgetUpdateService)
                    .getGlanceIds(MyGlanceWidget::class.java)
                    .forEach { glanceId ->
                        MyGlanceWidget().update(this@WidgetUpdateService, glanceId)
                    }
                delay(60 * 1000)
            }
        }
        return START_STICKY
    }

    override fun onDestroy() {
        super.onDestroy()
        job.cancel()
    }

    override fun onBind(intent: Intent?): IBinder? = null
}
  1. 关联Widget生命周期启停服务
    在Glance Widget的生命周期方法中启动/停止服务:
class MyGlanceWidget : GlanceAppWidget() {
    override fun provideGlance(context: Context, id: GlanceId) {
        setContent {
            Text("当前时间:${System.currentTimeMillis()}")
        }
    }

    override fun onEnabled(context: Context) {
        super.onEnabled(context)
        // 首次添加Widget时启动服务
        val intent = Intent(context, WidgetUpdateService::class.java)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(intent)
        } else {
            context.startService(intent)
        }
    }

    override fun onDisabled(context: Context) {
        super.onDisabled(context)
        // 所有Widget实例被删除时停止服务
        val intent = Intent(context, WidgetUpdateService::class.java)
        context.stopService(intent)
    }
}

方案二:AlarmManager 精确闹钟

通过精确重复闹钟触发广播,在广播接收器中刷新Widget,适合不需要持续后台运行的场景。

实现步骤

  1. 添加权限声明
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <!-- Android 12+ 精确闹钟权限 -->
<uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- 可选,防止设备休眠错过触发 -->
  1. 创建更新广播接收器
class WidgetUpdateReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        context ?: return
        // 刷新Widget
        GlanceAppWidgetManager(context)
            .getGlanceIds(MyGlanceWidget::class.java)
            .forEach { glanceId ->
                MyGlanceWidget().update(context, glanceId)
            }
        // 重新设置下一次闹钟(setExactAndAllowWhileIdle为单次触发)
        val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val nextIntent = Intent(context, WidgetUpdateReceiver::class.java)
        val nextPendingIntent = PendingIntent.getBroadcast(
            context,
            0,
            nextIntent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
        val nextTriggerMillis = System.currentTimeMillis() + 60 * 1000
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (alarmManager.canScheduleExactAlarms()) {
                alarmManager.setExactAndAllowWhileIdle(
                    AlarmManager.RTC_WAKEUP,
                    nextTriggerMillis,
                    nextPendingIntent
                )
            }
        } else {
            alarmManager.setExactAndAllowWhileIdle(
                AlarmManager.RTC_WAKEUP,
                nextTriggerMillis,
                nextPendingIntent
            )
        }
    }
}
  1. 注册广播接收器
    在AndroidManifest.xml中添加:
<receiver
    android:name=".WidgetUpdateReceiver"
    android:exported="false" />
  1. 在Widget中初始化闹钟
class MyGlanceWidget : GlanceAppWidget() {
    // ... Widget布局代码省略

    override fun onEnabled(context: Context) {
        super.onEnabled(context)
        val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val intent = Intent(context, WidgetUpdateReceiver::class.java)
        val pendingIntent = PendingIntent.getBroadcast(
            context,
            0,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
        val triggerAtMillis = System.currentTimeMillis() + 60 * 1000
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (alarmManager.canScheduleExactAlarms()) {
                alarmManager.setExactAndAllowWhileIdle(
                    AlarmManager.RTC_WAKEUP,
                    triggerAtMillis,
                    pendingIntent
                )
            }
        } else {
            alarmManager.setExactAndAllowWhileIdle(
                AlarmManager.RTC_WAKEUP,
                triggerAtMillis,
                pendingIntent
            )
        }
    }

    override fun onDisabled(context: Context) {
        super.onDisabled(context)
        // 所有Widget删除时取消闹钟
        val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val intent = Intent(context, WidgetUpdateReceiver::class.java)
        val pendingIntent = PendingIntent.getBroadcast(
            context,
            0,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
        alarmManager.cancel(pendingIntent)
    }
}

注意事项

  • 系统稳定性:前台服务稳定性更高,但会显示常驻通知;AlarmManager方案在设备深度休眠时可能出现触发延迟,需结合RTC_WAKEUP和唤醒锁优化。
  • 电池消耗:每分钟更新会增加电池开销,建议提供用户可调整更新频率的选项。
  • 权限适配:严格按照Android版本要求申请对应权限,避免功能失效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 06:25:13