定期工作请求是否应该立即执行?
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
内执行
编辑(长话短说;博士)
我没有意识到周期性工作请求的构造函数不止一个。导致我困惑的线索在已接受答案的评论中。
背景
我在安排工作时尝试解决一些特殊情况。其中之一涉及立即开始工作,然后创建定期工作请求。我在 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
内执行