Reputation: 3593
I have a project that runs a Live WallpaperService
that displays an image from a web source chosen by the user.
The wallpaper is updated via a PeriodicWorkRequest
that fetches the latest image from said web source at a frequency chosen by the user.
When the device is idle, Doze Mode and App Standby are enforced as expected and updates are postponed until user starts using his device.
I am using Constraints
to ensure internet connectivity is available and battery is not low.
However, updates are not resuming when device is no longer idle.
In order to find out more about what is going on, I am calling WorkManager #getWorkInfosForUniqueWorkFlow()
to display debug data returned by WorkInfo
. To my surprise, my PeriodicWorkRequest
is marked as WorkInfo.State#FAILED
, meaning isFinished = true
and the nextScheduleTimeMillis
is set to a date far, very far into the future, somewhere around 292 millions years from now, in August 😅. Most likely a constant (possibly Long.MAX_VALUE
?)
Here some code:
private val constraints: Constraints by lazy {
Constraints.Builder().run {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(false)
}
setRequiredNetworkType(NetworkType.CONNECTED)
setRequiresBatteryNotLow(true)
}.build()
}
fun scheduleUpdates() {
val existingWork: List<WorkInfo> = workManager.getWorkInfosForUniqueWork(uniqueWorkName = WALLPAPER_UPDATE_WORKER_TAG).await()
val existingWorkId: UUID? = existingWork.firstOrNull()?.id
val periodicWorkRequest = PeriodicWorkRequest
.Builder(WallpaperUpdaterWorker::class.java, refreshRate.toMillis(), TimeUnit.MILLISECONDS)
.setInitialDelay(refreshRate.toMillis(), TimeUnit.MILLISECONDS)
.setInputData(
workDataOf(
WORKER_PARAM_WEBCAM_ID to websource.id,
WORKER_PARAM_WEBCAM_URL to websource.baseUrl,
)
)
.setConstraints(constraints)
.apply { existingWorkId?.let(::setId) } // to update in case user changes the frequency or the web source
.build()
workManager.enqueueUniquePeriodicWork(
uniqueWorkName = WALLPAPER_UPDATE_WORKER_TAG,
existingPeriodicWorkPolicy = ExistingPeriodicWorkPolicy.UPDATE,
request = periodicWorkRequest,
)
}
When the WallpaperUpdaterWorker
executes, the returned Result
policy is as follow:
Result.failure()
if any of the two WorkerParameters
are missing orResult.retry()
in case exceptions were caught during update work orResult.success()
when everything went fine.So I am surprised that my WorkInfo.State
is FAILED
without any more information and not ENQUEUED
.
In order to mitigate such issue, the user may disable battery optimisation manually but that does not seem to work at all. Also, app suspension (from App Standby ?) cannot be turned off ; this I believe because my app has a live WallpaperService
so the app is always running.
=> How can I recover from that state ? How can I ensure that it does not happen and updates gracefully resumes after leaving idle state (like after a night) ?
Upvotes: 0
Views: 18