Spyros G
Spyros G

Reputation: 115

JobScheduler - How to skip first job run of periodic job?

in my app i have set a periodic job that is set to run every 30 minutes. The first job run occurs right when I do schedule that periodic job, which is not wanted in my case. What I want is to skip the first run so that it will run for the first time after 30+ minutes.

My two thoughts on how to approach this was to either have it not run at all for the first 30 minutes somehow (some kind of delay), or mark the first job run as done before even having the chance to start. Unfortunately I have not found any method in JobInfo that would allow me to do any of those.

Another workaround that would fulfill my needs would be to somehow limit the jobs to only occur while app is in the background. It does not entirely solve the issue but it could serve as a workaround in my case.

Following is my current code for scheduling the periodic job:

private void scheduleJob() {
    ComponentName componentName = new ComponentName(this, myRecurringTask.class);
    JobInfo info = new JobInfo.Builder(JOB_ID, componentName)
            .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
            .setPersisted(true)
            .setPeriodic(1800000)
            .build();
    JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
    scheduler.schedule(info);
}

I hope someone has run into the same situation and can help me resolve it... Thank you!

Upvotes: 2

Views: 938

Answers (1)

Sam Chen
Sam Chen

Reputation: 8857

Use WorkManager for scheduling backgound work, see introduction here.

1. Add Dependency:

implementation "androidx.work:work-runtime-ktx:2.4.0"

2. Create Worker Class:

class DataRefresher(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
    override suspend fun doWork(): Result {                 //will run on background thread
        //your logic

        return try {
            //your logic

            Result.success()
        } catch (e: HttpException) {
            Result.retry()
        }
    }
}

3. Create Application Class:

class DevBytesApplication : Application() {
    private val backgroundScope = CoroutineScope(Dispatchers.Default)       //standard background thread

    override fun onCreate() {                           //called when app launches, same as Activity
        super.onCreate()

        initWork()
    }

    private fun initWork() {
        backgroundScope.launch {                        //run in background, not affecting ui
            setupDataRefreshingWork()
        }
    }

    @SuppressLint("IdleBatteryChargingConstraints")
    private fun setupDataRefreshingWork() {
        val constraints = Constraints.Builder()
            .setRequiredNetworkType(NetworkType.UNMETERED)          //when using wifi
            .setRequiresBatteryNotLow(true)
            .setRequiresCharging(true)
            .setRequiresDeviceIdle(true)                    //when not running heavy task
            .build()

        val repeatingRequest = PeriodicWorkRequestBuilder<DataRefresher>(1, TimeUnit.DAYS)      //【15 minutes is minimum!!】
            .setConstraints(constraints)
            .setInitialDelay(30, TimeUnit.MINUTES)        //【initial delay!!】
            .build()

        WorkManager.getInstance(this).enqueueUniquePeriodicWork(
            DataRefresher::class.java.simpleName,               //work name
            ExistingPeriodicWorkPolicy.KEEP,                    //if new work comes in with same name, discard it
            repeatingRequest
        )
    }
}

4. Setup AndroidManifest:

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.devbytestest">

    <application
        android:name=".DevBytesApplication"                 //【here, must!!!】
    
        ...

    </application>

</manifest>

Upvotes: 3

Related Questions