Android的WorkerManager何时会停止一个Worker?

9
我们有一个使用WorkManager处理后台同步工作的Android应用程序。我们的同步工作者是这样的:
public class SyncWorker extends Worker {

    [...]

    @NonNull
    @Override
    public Result doWork() {

        if (canNotRetry(getRunAttemptCount())) {
            // This could seem unreachable, consider removing... or not... because if stopped by the
            // system, the work might be retried by design
            CBlogger.INSTANCE.log([...]);
            return Result.success();
        }

        boolean syncOk = false;

        //Sync
        try (Realm realm = Realm.getDefaultInstance()) {

            // Doing sync related ops & network calls
            // checking this.isStopped() between operations to quit
            // sync activity when worker has to be stopped

            syncOk = true;
        } catch (Throwable throwable) {
            CBlogger.INSTANCE.log([...]);
        }

        // On error, continue with following code to avoid any logic in catch
        // This method must NOT throw any unhandled exception to avoid unique work to be marked as failed
        try {

            if (syncOk) {
                return Result.success();
            }

            if (canNotRetry(getRunAttemptCount() + 1)) {
                CBlogger.INSTANCE.log([...]);
                return Result.success();
            } else {
                CBlogger.INSTANCE.log([...]);
                return Result.retry();
            }
        } catch (Throwable e) {
            CBlogger.INSTANCE.log([...]);
            return Result.success();
        }
    }

    private boolean canNotRetry(int tryNumber) {
        // Check if the work has been retry too many times
        if (tryNumber > MAX_SYNC_RETRY_COUNT) {
            CBlogger.INSTANCE.log([...]);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public void onStopped() {
        CBlogger.INSTANCE.log([...]);
    }
}

工作由帮助类的专用方法安排:
    public static void scheduleWorker(Context context, String syncPolicy, ExistingWorkPolicy existingWorkingPolicy){

        Constraints constraints = new Constraints.Builder()
                .setRequiresCharging(false)
                .setRequiredNetworkType(NetworkType.CONNECTED)
                .build();

        Data.Builder data = new Data.Builder();
        data.putString(context.getResources().getString(R.string.sync_worker_policy), syncPolicy);

        Log.d(TAG, "Scheduling one-time sync request");
        logger.info("Scheduling one-time sync request");
        OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder
                (SyncWorker.class)
                .setInputData(data.build())
                .setConstraints(constraints)
                .setBackoffCriteria(
                        BackoffPolicy.LINEAR,
                        OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
                        TimeUnit.MILLISECONDS)
                .build();

        WorkManager.getInstance(context).enqueueUniqueWork("OneTimeSyncWorker", existingWorkingPolicy, oneTimeWorkRequest);
    }

当用户单击“同步”按钮或由另一个工作程序调用时,将调用该函数,该工作程序每20分钟运行一次并以此方式调用helper的函数。
SyncWorkerManager.scheduleWorker(context, context.getResources().getString(R.string.sync_worker_policy_full), ExistingWorkPolicy.KEEP);

为了避免重复等待或运行,只有在没有等待或正在运行时才会排队新的同步。请注意,同步工作策略强制要求连接到网络。

这种策略总体上效果很好,但有时我们发现日志中Worker的onStopped()方法在SyncWorker启动后几秒钟(约10“)被调用。

我们知道,我们从外部不会编程停止特定的Worker,而且我们只会在注销过程中或新登录之前(也安排del周期性Worker)调用WorkManager.getInstance(context).cancelAllWork();,那么系统何时决定停止Worker并调用其onStopped()方法?

我知道这可能发生在以下情况下:

  • 约束不再满足(网络连接中断)
  • 工作程序超过了JobScheduler实现所施加的10分钟限制(我们的场景在Android 9设备上进行了测试)
  • 使用相同名称和REPLACE策略排队新的唯一工作(我们从未在SyncWorker应用中使用此策略,仅在PeriodicSyncWorker中使用)
  • 由于this bug而产生的虚假调用(我们使用“androidx.work:work-runtime:2.2.0”)

还有其他原因会导致工作程序停止吗?例如:

  • Doze模式
  • 应用待机桶
  • 应用后台限制(设置-->应用-->我的应用-->电池-->允许后台运行)
  • 应用电池优化(设置-->应用-->我的应用-->电池-->电池优化)

谢谢


1
我相信你在最后提到的所有四个问题。Doze模式非常强制性,会停止所有工作、网络等。话虽如此,我想知道如果用户短暂失去互联网访问权限(或者网络质量不佳),是否会导致Work Manager认为“网络已断开”,即使只有一秒钟的时间。 - Martin Marconcini
正如Martin Marconcini所提到的,所有的原因都可能是真实存在的,或者你的代码可能已经抛出了一个错误。无论如何,我听说在OnePlus设备中存在一个bug,会强制停止后台运行的应用程序(强制停止它们),这将需要重新启动应用程序才能再次开始同步。 - coroutineDispatcher
我同意,但是想象一下,Doze避免了Worker的启动,而不是在启动后突然停止它。也许应用待机存储桶会减少Worker的时间窗口? - Paolone
好的,没有亲自测试过,我想Doze模式不知道Work Manager是否正在运行任务。Doze决定进入省电模式并且会执行。我希望Ian Lake或者来自Google的其他人能看到这个并发表评论 :) - Martin Marconcini
据我所知,WorkManager旨在尊重Dose模式,因此我认为反过来是行不通的。 - coroutineDispatcher
1个回答

0

一个 Worker 可以被停止的原因有很多。你可以明确地要求它被取消,或者 WorkManager 可能会出于各种原因而停止它,这些原因在此处记录


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接