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

Android O设备闲置后收不到ACTION_SCREEN_ON广播及Widget更新异常求助

解决Android O+设备锁屏解锁后无法更新Widget的问题

嘿,这个问题我太熟了——Android 8.0(API 26)给后台行为加了一堆限制,刚好踩中了你遇到的场景!先给你拆解下根源:

从API26开始,系统直接禁止了静态注册接收隐式广播,ACTION_SCREEN_ON和ACTION_USER_PRESENT都属于这类广播。之前你用SDK25的时候没问题,是因为当时还没这个限制;现在升级到targetSdk26,哪怕Widget还在主屏幕上,只要应用进程被杀,静态注册的广播接收器完全不会被系统唤醒,自然触发不了你的JobService更新Widget。

下面给你几个针对性的解决方案,按推荐程度排序:

方案1:用WorkManager替代JobService(推荐)

WorkManager是Jetpack推出的任务调度组件,比原生JobService更灵活,还能跨版本兼容,关键是即使应用被杀,满足条件时任务依然会执行。你可以给任务设置「设备退出空闲状态」的约束,刚好对应用户解锁手机的场景:

// 构建任务约束:设备不处于空闲状态(解锁后设备会退出空闲)
Constraints constraints = new Constraints.Builder()
        .setRequiresDeviceIdle(false)
        .setRequiresBatteryNotLow(true) // 可选,避免低电量时消耗资源
        .build();

// 创建单次更新任务
OneTimeWorkRequest widgetUpdateWork = new OneTimeWorkRequest.Builder(WidgetUpdateWorker.class)
        .setConstraints(constraints)
        .build();

// 在需要触发的时机(比如Widget添加、应用启动、动态广播收到解锁事件时)入队任务
WorkManager.getInstance(context).enqueue(widgetUpdateWork);

然后在WidgetUpdateWorker里完成数据拉取和Widget更新:

public class WidgetUpdateWorker extends Worker {
    public WidgetUpdateWorker(@NonNull Context context, @NonNull WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public Result doWork() {
        // 1. 调用后端接口获取最新数据
        // 2. 更新Widget
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
        int[] widgetIds = appWidgetManager.getAppWidgetIds(
                new ComponentName(getApplicationContext(), YourWidgetProvider.class)
        );
        for (int id : widgetIds) {
            RemoteViews views = new RemoteViews(getApplicationContext().getPackageName(), R.layout.widget_layout);
            // 把新数据设置到views上
            appWidgetManager.updateAppWidget(id, views);
        }
        return Result.success();
    }
}

方案2:结合动态广播+Widget系统回调

如果需要更实时的解锁更新,可以在应用存活时动态注册ACTION_USER_PRESENT广播,收到后立即触发更新;同时利用Widget的系统回调兜底(比如用户解锁后系统刷新Widget时):

动态注册广播(仅应用存活时有效)

在你的主Activity或者前台Service里注册:

private BroadcastReceiver userPresentReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
            // 直接触发Widget更新或者Work任务
            updateWidgets(context);
        }
    }
};

@Override
protected void onResume() {
    super.onResume();
    IntentFilter filter = new IntentFilter(Intent.ACTION_USER_PRESENT);
    registerReceiver(userPresentReceiver, filter);
}

@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(userPresentReceiver);
}

利用WidgetProvider的onUpdate兜底

当系统刷新Widget时(比如解锁后主屏幕加载),会调用onUpdate,这里可以触发一次更新:

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    super.onUpdate(context, appWidgetManager, appWidgetIds);
    // 触发Work任务更新数据
    scheduleWidgetUpdate(context);
}

方案3:慎用辅助功能(仅特殊场景)

如果以上方案都满足不了你的实时需求,还有个极端选项:用Accessibility Service监听解锁事件。但这个需要用户手动授权,而且只能用于辅助功能场景,不能滥用——毕竟用户会反感不必要的权限请求。

避坑提醒

  • 别想着用前台服务保活进程,Android 12+对前台服务限制极严,还会增加电量消耗,用户很可能直接关掉你的权限。
  • 不管用哪种方案,更新Widget时一定要遍历所有已添加的Widget实例,别漏更了用户添加的多个Widget。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:27:47