You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

WorkManager在三星Galaxy S10(Android 9)后台/进程被杀时失效问题咨询

解决三星Galaxy S10上WorkManager周期性任务后台失效问题

我之前在三星设备上也碰到过一模一样的WorkManager周期性任务失效的情况——模拟器正常运行,但真机后台或关闭后任务就停了。核心原因基本都是三星定制系统的电池优化策略在拦截后台任务,结合你的代码和场景,给你几个针对性的解决方案:

1. 优先关闭应用的电池后台限制

三星有自己独立的后台任务管控机制,哪怕设备处于充电状态、API版本符合要求,它也会默认限制非活跃应用的后台活动。你可以手动操作设置:

  • 打开手机「设置」→「电池和设备维护」→「电池」→「后台使用限制」
  • 找到你的应用「Bible Cucu」,把后台限制改成「无限制」

如果想在代码里引导用户跳转到设置页面,可以添加这段Intent(建议弹窗提示用户手动操作,不要强制跳转):

Intent intent = new Intent();
String packageName = context.getPackageName();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (pm != null && !pm.isIgnoringBatteryOptimizations(packageName)) {
    intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
    intent.setData(Uri.parse("package:" + packageName));
    context.startActivity(intent);
}

注意:这个操作需要REQUEST_IGNORE_BATTERY_OPTIMIZATIONS权限,Google Play对滥用该权限的应用有审核限制,因此仅作为提示引导即可,不要自动申请权限。

2. 验证WorkManager任务是否真的没执行

有时候任务实际已经运行,但因为通知没显示导致你误以为失效。建议在doWork()方法里添加本地日志记录,确认任务是否真的被调度:

@Override
public Result doWork() {
    Log.d(TAG, "On dowork");
    // 添加本地文件日志,方便后台查看任务执行情况
    try {
        File logDir = getApplicationContext().getExternalFilesDir(null);
        File logFile = new File(logDir, "cucu_work_log.txt");
        FileWriter writer = new FileWriter(logFile, true);
        String logContent = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + ": Task executed\n";
        writer.write(logContent);
        writer.close();
    } catch (IOException e) {
        Log.e(TAG, "Failed to write log", e);
    }
    
    // 保留你原有的业务逻辑
    if(ctx!=null) {
        SharedPreferences prefs = ctx.getSharedPreferences("CUCU", ctx.MODE_PRIVATE);
        prefs.edit().putLong("lastcucu",new Date().getTime()).apply();
        showNotification(ctx);
    }
    return Result.success();
}

之后你可以通过文件管理器在Android/data/你的应用包名/files/目录下找到日志文件,确认任务是否真的在后台执行了。

3. 确保通知渠道正确创建

API 26及以上必须创建通知渠道才能显示通知,你代码里用了channel_1,但如果没有提前创建这个渠道,后台可能无法弹出通知。建议在Application的onCreate()方法里添加渠道创建代码:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        createNotificationChannel();
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence channelName = "Bible Cucu 提醒";
            String channelDesc = "显示周期性圣经内容提醒";
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel("channel_1", channelName, importance);
            channel.setDescription(channelDesc);
            
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }
}

别忘了在Manifest文件里注册这个自定义Application。

4. 调整WorkManager的弹性时间(可选)

你当前的周期设置是15分钟周期 + 5分钟弹性,虽然符合WorkManager的最小周期要求,但三星的调度器可能对弹性时间较长的任务管控更严格。可以尝试把弹性时间调小,比如设置为1分钟:

PeriodicWorkRequest work = new PeriodicWorkRequest.Builder(WorkerCucu.class, 
    15, TimeUnit.MINUTES, 
    1, TimeUnit.MINUTES).build();

这个调整效果因人而异,主要用于测试是否能绕过三星的调度限制。

5. 备选方案:结合AlarmManager(针对API 28及以下)

如果以上方法都无效,对于API 28及以下的设备,可以考虑用AlarmManagersetExactAndAllowWhileIdle()实现周期性任务——虽然WorkManager已经封装了这些逻辑,但三星的定制系统可能对原生AlarmManager的兼容性更好。示例代码如下:

// 设置首次触发时间
long triggerAtMillis = System.currentTimeMillis() + 15 * 60 * 1000;
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

// 针对API 23+的Doze模式,使用setExactAndAllowWhileIdle
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
} else {
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtMillis, 15 * 60 * 1000, pendingIntent);
}

然后在AlarmReceiveronReceive()方法里执行显示通知的逻辑,或者调用WorkManager的一次性任务。

建议先从第一步的电池优化设置开始尝试,这是三星设备后台任务失效最常见的原因,大部分情况下调整后就能正常工作了。

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

火山引擎 最新活动