定期工作请求是否应该立即执行?

Are periodic work requests supposed to execute immediately?

编辑(长话短说;博士)

我没有意识到周期性工作请求的构造函数不止一个。导致我困惑的线索在已接受答案的评论中。

背景

我在安排工作时尝试解决一些特殊情况。其中之一涉及立即开始工作,然后创建定期工作请求。我在 Android 的 PeriodicWorkRequest documentation:

中找到了这个

This work executes multiple times until it is cancelled, with the first execution happening immediately or as soon as the given Constraints are met.

我认为这意味着工作会在创建请求时执行。但是,这不是我的测试实施中发生的情况。 (对于这项工作,不需要 CoroutineWorker 或网络连接约束,但它适用于我的业务需求,所以我正在测试它)

开始工作

object WorkerManager {
    private val TAG = "WORKER_MANAGER_TEST"

    fun buildWorkRequest(
        startingNumber: Int,
        context: Context
    ) {
        val constraints =
            Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()

        val workRequest = PeriodicWorkRequest.Builder(
            PeriodicWorker::class.java,
            1,
            TimeUnit.HOURS,
            15,
            TimeUnit.MINUTES
        )
            .setInputData(
                workDataOf(Constants.INPUT_DATA_NUMBER to startingNumber)
            )
            .addTag(Constants.PERIODIC_WORKER_TAG)
            .setConstraints(constraints)
            .build()

        WorkManager.getInstance(context).enqueueUniquePeriodicWork(
            Constants.PERIODIC_WORKER_NAME,
            ExistingPeriodicWorkPolicy.REPLACE,
            workRequest
        )

        Log.d(TAG, "Worker started. Starting number: $startingNumber")
    }
}

工人:

class PeriodicWorker(context: Context, workerParams: WorkerParameters): CoroutineWorker(context,
    workerParams
) {
    companion object {
        var isInit = false
        var count: Int = 1
    }

    override suspend fun doWork(): Result = try {
        if (!isInit) {
            count = inputData.getInt(Constants.INPUT_DATA_NUMBER, Constants.DEFAULT_DATA_NUMBER)
            isInit = true
        } else {
            count += 1
        }

        Repository.updateNumber(count)

        Result.success()
    } catch (exception: Exception) {
        Result.failure()
    }
}

回购:

object Repository {
    private val TAG = "REPOSITORY_TAG"
    private val _number = MutableStateFlow(0)
    val number: StateFlow<Int> = _number

    suspend fun updateNumber(number: Int) {
        Log.d(TAG, "Number updated to: $number")
        _number.emit(number)
    }
}

ViewModel:

class NumberViewModel : ViewModel() {
    private val _count = MutableLiveData(0)
    val count: LiveData<Int> = _count

    init {
        viewModelScope.launch {
            Repository.number.collect {
                _count.postValue(it)
            }
        }
    } 
}

结果

我以10为起始编号开始了一个worker。

日志:

8:45am  - Worker started. Starting number: 10
9:37am  - Number updated to: 10                 // work executed
10:37am - Number updated to: 11                 // work executed
11:37am - Number updated to: 12                 // work executed

设备信息

OS 版本 28 -- 三星 SM-T390

我的结论

约束条件 - 不能成为问题。我在上述测试中有网络连接,这是唯一给定的限制。

电池优化 - 我确定此应用在 运行 此测试之前已列入白名单。

所以总而言之,PeriodicWorkRequests 不要 立即执行工作。 Android 文档应该改为:

This work executes multiple times until it is cancelled, with the first period beginning immediately. The first work execution then happens within the first flex interval given the constraints are met.

问题

我的结论看起来合理吗?有什么我没有考虑到的吗?

你想多了。请转储 JS:

https://developer.android.com/topic/libraries/architecture/workmanager/how-to/debugging

使用adb shell dumpsys jobscheduler

然后检查转储中不满足的约束是什么:

  Required constraints: TIMING_DELAY CONNECTIVITY [0x90000000]
  Satisfied constraints: DEVICE_NOT_DOZING BACKGROUND_NOT_RESTRICTED WITHIN_QUOTA [0x3400000]
  Unsatisfied constraints: TIMING_DELAY CONNECTIVITY [0x90000000]

还有:

Minimum latency: +1h29m59s687ms

据我了解这个构造函数:

          PeriodicWorkRequest.Builder(Class<? extends ListenableWorker> workerClass, 
    long repeatInterval, TimeUnit repeatIntervalTimeUnit,
 long flexInterval, TimeUnit flexIntervalTimeUnit)

意味着您的工作将在 repeatInterval

flexInterval 内执行