【问题标题】:Work Manager not scheduling Work with setInitialDelay工作管理器未安排使用 setInitialDelay 的工作
【发布时间】:2018-11-01 08:07:11
【问题描述】:

所以我有一个 Worker,它必须从计划的第二天开始运行。因此,如果工作在今天晚上 8 点启动,那么我需要在第二天早上 9 点执行工作。所以我使用OneTimeWorkRequestsetInitialDelay()

这里是代码

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)

但是我查了一下,第二天醒来时工作并没有执行。 为什么不安排呢?我计算第二天时间戳的方式有问题吗?

【问题讨论】:

  • OneTimeWorkRequestBuilder&lt;T&gt; 是您的自定义类吗?你想因为参数中传递类类型而消除标准构建器吗?
  • 这只是工作管理器依赖项附带的 kotlin 快捷方式。您可以在末尾添加 -ktx 以获得每个架构组件的 kotlin 友好语法。
  • 干得好! ....

标签: android android-workmanager


【解决方案1】:

正如我们在 Google 的问题跟踪器中看到的 here

不幸的是,有些设备会从最近的菜单中终止应用程序作为强制停止。股票 Android 不这样做。当应用程序被强制停止时,它无法执行作业、接收警报或广播等。不幸的是,我们无法解决它 - 问题出在操作系统上,没有解决方法。

因此,您需要Service 来维持您的应用程序的运行。此外,当Service 终止时(不管是什么原因),它应该重新启动并初始化您的工作人员以确保其执行并保持工作人员任务处于活动状态。这是使用 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>

【讨论】:

  • 当我按照自己的方式进行操作时,正如我在日志中看到的那样安排了工作。此外,我将 ID 保存到共享首选项中,以便确认工作已安排好。从 IntentService 安排工作有什么不同?因为一旦安排好,无论从哪里运行,它都会按预期运行,对吗? IntentService 的调度与 Fragment 的调度有何不同?
  • WorkManager 工作在应用层,而不是操作系统。我的意思是它在您的应用程序进程中运行,因此当进程被终止时,工作管理器对象及其调度的工作人员将完全从内存中删除。如果您将任务安排在 10 秒后,而不是明天上午 9 点,然后清除最近的应用程序,您将看到您的计划工作人员不会运行。上述服务避免了长时间杀死应用程序。终止后,它会重新启动并重新安排您的任务,并确保我们的工作任务仍然驻留在内存中。
  • @SriramR:你测试了吗?
  • 是的。有时工人按预期工作。有时它不会。我只是想调试它。
  • 我第一次尝试时它按预期工作。在那之后,它没有工作,工人没有被处决。第一次,出于测试目的,我将 Initial delay 设置为从我尝试开始的 10 分钟。下次我在第二天早上 9 点试了一下。那没用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多