Daily Job on a specific time for Android 8.0+

Viewed 2222

I’ve been trying to figure out how to use any of background task APIs in order to create a Work Request that fires every day on a specific time of the day on devices running Android 8.0+. The time must be set by the user locally on the device (meaning no GCM).

Is that even possible anymore? Legacy devices with AlarmManager works wonders, but as far as I am aware all pending intents are cleared when the app gets Force Stopped so it’s a no go now.

WorkManager's PeriodicWorkRequest doesn't allow you to set the time to start the Work. I looked into creating a delayed OneTimeWorkRequest and schedule the next one after it runs, but nothing ensures that the work will run on the time I want.

Evernote's Android-Job library has issues with the DailyJob too (https://github.com/evernote/android-job/issues/318).

Any suggestions/ideas more than welcome.

3 Answers

You could just use a OneTimeWorkRequest which schedules a copy of itself before it returns a Result.

class TestWorker: Worker() {
   fun doWork(): Result {
     val nextWorkRequest = OneTimeWorkRequestBuilder<TestWorker>()
     nextWorkRequest.withInitialDelay(24, TimeUnit.HOURS)
     WorkManager.getInstance().enqueue(nextWorkRequest)
     return Result.SUCCESS;
   }
}

Start off the first work request with a:

 val firstWorkRequest = OneTimeWorkRequestBuilder<TestWorker>()
 firstWorkRequest.withInitialDelay(24, TimeUnit.HOURS)
 WorkManager.getInstance().enqueue(firstWorkRequest)

Thus you get something which looks like a PeriodicWorkRequest with the timing you need.

New PeriodicWorkRequests now support initial delays. So you take the required time from the user, calculate difference between userTime and Now and just set the delay. Unlike AlarmManeger it is very reliable. The only problem is Android fires Worker when it finds the best moment for it (no other work to do), so it may be started with a little delay (usually not more than a few minutes).

Did you try using chained tasks in WorkManager. First Schedule OneTimeWorkRequest, then chain it with PeriodicWorkRequest. Like:

WorkManager.getInstance()
.beginWith(workA)
.then(workB) 

where workA is OneTimeWorkRequest and workB is PeriodicWorkRequest

Related