So I have a Worker that has to run the next day from when it's scheduled. So if the work is activated at today night 8PM, then I need the work to be executed at next day 9AM. So I am using OneTimeWorkRequest
with a setInitialDelay()
.
Here is the code
val currentTime = System.currentTimeMillis()
// calculate the timestamp for next dat 9AM
val calendar = Calendar.getInstance()
calendar.set(Calendar.HOUR_OF_DAY, 9)
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
// next day
calendar.add(Calendar.DAY_OF_MONTH, 1)
val tomorrowTime = calendar.timeInMillis
val timeDiffBetweenNowAndTomorrow = tomorrowTime - currentTime
Timber.i("Tomorrow date is ${calendar.timeInMillis}")
Timber.i("Difference between now and tomorrow ${timeDiffBetweenNowAndTomorrow}")
val randomWorkRequest = OneTimeWorkRequestBuilder<RandomWallpaperWorker>()
.setInitialDelay(timeDiffBetweenNowAndTomorrow, TimeUnit.MILLISECONDS)
.build()
WorkManager.getInstance().enqueue(randomWorkRequest)
But I checked and the work wasn't executed when I woke up the next day. Why isn't it being scheduled? Is there something wrong the way I calculate the timestamp of the next day?
As we see here in Google's issue tracker:
Unfortunately, some devices implement killing the app from the recents menu as a force stop. Stock Android does not do this. When an app is force stopped, it cannot execute jobs, receive alarms or broadcasts, etc. So unfortunately, it's infeasible for us to address it - the problem lies in the OS and there is no workaround.
As a result, you need a Service
to maintain your app alive. Also when the Service
is terminated (doesn't matter what's the reason), it should start again and initialize your worker to be sure about its execution and keep the worker tasks alive. Here is an implementation of this idea using a STICKY
IntentService
.
WallpaperService.kt
import android.app.IntentService
import android.app.Service
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import java.util.*
import java.util.concurrent.TimeUnit
class WallpaperService : IntentService("WallpaperService") {
override fun onHandleIntent(intent: Intent?) {
intent?.apply {
when (intent.action) {
ACTION_SETUP_WORKER -> {
setupWorker()
}
}
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
// Define service as sticky so that it stays in background
return Service.START_STICKY
}
private fun setupWorker() {
val calendar = Calendar.getInstance()
val currentTime = calendar.timeInMillis
// for removing from recent apps test
// calendar.add(Calendar.SECOND, 10)
calendar.set(Calendar.HOUR_OF_DAY, 9)
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
calendar.set(Calendar.MILLISECOND, 0)
calendar.add(Calendar.DAY_OF_MONTH, 1)
val tomorrowTime = calendar.timeInMillis
val timeDiffBetweenNowAndTomorrow = tomorrowTime - currentTime
Log.i("WallpaperService", "************ Tomorrow date is ${calendar.timeInMillis}")
Log.i("WallpaperService", "************ Difference between now and tomorrow $timeDiffBetweenNowAndTomorrow")
val randomWorkRequest = OneTimeWorkRequestBuilder<RandomWallpaperWorker>()
.setInitialDelay(timeDiffBetweenNowAndTomorrow, TimeUnit.MILLISECONDS)
.build()
WorkManager.getInstance().enqueue(randomWorkRequest)
}
companion object {
const val ACTION_SETUP_WORKER = "ACTION_SETUP_WORKER"
fun setupWorker(context: Context) {
val intent = Intent(context, WallpaperService::class.java)
intent.action = ACTION_SETUP_WORKER
context.startService(intent)
}
}
}
RandomWallpaperWorker.kt
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters
class RandomWallpaperWorker(val context: Context, params: WorkerParameters) : Worker(context, params) {
override fun doWork(): Result {
// Do what you want here...
Log.e("RandomWallpaperWorker", "***************** DONE!" )
WallpaperService.setupWorker(context)
return Result.SUCCESS
}
}
MainActivity.kt
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
WallpaperService.setupWorker(applicationContext)
}
}
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.aminography.workerapplication">
<application ... >
...
<service android:name=".WallpaperService" android:enabled="true"/>
</application>
</manifest>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With