【问题标题】:JobScheduler - How to skip first job run of periodic job?JobScheduler - 如何跳过定期作业的第一次作业?
【发布时间】:2021-05-22 10:41:57
【问题描述】:

在我的应用程序中,我设置了一个定期作业,该作业设置为每 30 分钟运行一次。 第一次作业运行发生在我安排定期作业时,这在我的情况下是不需要的。 我想要的是跳过第一次运行,以便在 30 多分钟后第一次运行。

关于如何解决这个问题,我的两个想法是要么让它在前 30 分钟内不运行(某种延迟),要么在有机会开始之前将第一个作业运行标记为已完成。 不幸的是,我在JobInfo 中没有找到任何可以让我做任何这些的方法。

另一个可以满足我需求的解决方法是以某种方式将作业限制为仅在应用程序处于后台时发生。它并不能完全解决问题,但在我的情况下它可以作为一种解决方法。

以下是我当前用于安排定期作业的代码:

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);
}

我希望有人遇到过同样的情况并可以帮助我解决它...谢谢!

【问题讨论】:

  • 初始延迟在WorkManager:stackoverflow.com/questions/51229826/…中可用
  • 感谢@SamChen 的回复。我以前从未听说过WorkManager,我只是在检查它的功能集与JobScheduler 相比,它确实带来了很多改进,同时仍然向后兼容。如果我找不到JobScheduler 的任何解决方案,我将迁移到WorkManager,我肯定会将它用于新应用程序!

标签: android delay android-jobscheduler periodic-task


【解决方案1】:

使用WorkManager安排后台工作,见简介here

1.添加依赖:

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

2。创建工人阶级:

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.创建应用程序类:

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.设置 AndroidManifest:

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

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

    </application>

</manifest>

【讨论】:

  • 感谢您的回答。我肯定会考虑迁移到WorkManager,因为它恰好具有我本机需要的选项。目前,我通过跟踪作业在 SharedPreferences 中运行的时间并在第一次运行时跳过作业操作来实施解决方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-09
  • 2017-08-18
  • 2018-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多