Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Work Manager not scheduling Work with setInitialDelay

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?

like image 913
Sriram R Avatar asked Oct 17 '22 11:10

Sriram R


1 Answers

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>
like image 120
aminography Avatar answered Oct 21 '22 00:10

aminography