APP被杀也能执行的任务,WorkManager介绍以及用法

WorkManagerAndroid Jetpack库的一部分,用于简化在Android应用程序中执行后台任务的管理。它提供了一种灵活、可靠的方式来调度和执行异步任务,而无需开发人员过多关注任务的管理和设备状态。

介绍

下面是WorkManager的一些关键特性和用途:

  1. 任务调度: WorkManager允许你定义需要执行的任务,包括延迟执行、定时执行和根据触发条件执行的任务。你可以创建单次或重复性任务。
  2. 任务链: 你可以创建任务链,将多个任务按顺序排列,以确保它们以特定顺序执行。这对于处理复杂的工作流非常有用。
  3. 约束: WorkManager支持约束,这意味着你可以指定任务执行的条件,例如在特定网络状态下、设备充电时等。这有助于减少不必要的任务执行,提高电池寿命和性能。
  4. 后台适应性: WorkManager能够选择最佳的后台任务调度方法,以适应不同Android版本和制造商的设备。它在Android 2.3(API级别 9)及更高版本中运行,并针对不同版本使用不同的后台任务调度API。
  5. 持久性: WorkManager具有内置的持久性,可以保证任务即使在设备重启后也能够继续执行。这有助于确保任务完成,而不会丢失。
  6. 观察和反馈: 你可以观察任务的执行状态,包括成功、失败、取消等。这为有效的错误处理提供了机会。
  7. 简化多线程: WorkManager处理了多线程的复杂性,使任务管理和执行更加简单。

WorkManager的推荐使用场景如下。

  1. 如果你需要定期执行某些任务,即使重启手机和关闭APP。
  2. 如果你有一些任务,需要在用户有Wi-Fi或充电状态的时候执行,如上传任务。
  3. 如果你的任务是一个复杂的任务链,WorkManager可以将其中一个任务的输出作为另一个任务的输入,以便实现更复杂的任务流程,例如图片处理。
  4. 可用于在后台定期同步应用数据,以确保数据保持最新。
  5. 如果你想要发送日志到后端。

存在的坑,因为有很多安卓厂商为了保证电池的续航,所以当你的应用被退出后,任务的执行可能不是很及时(特别是VIVO),除非在设置页面将APP的电池优化关闭。

与协程和AlarmManager的区别

API 推荐用法 与WorkManager的关系
协程 用来执行所有不需要维持的异步任务。 协程是用来处理非主线程工作任务的。因为协程退出APP后就会被停止,所以如果想要确保工作在退出APP后还能执行的话请使用WorkManger
AlarmManager 定时提醒。 AlarmManager会将设备从 Doze mode中唤醒,因此会比较耗电。除了需要精确执行提醒或者通知外,请使用WorkManager代替。

引入WorkManager

groovy 复制代码
// Java用这个
implementation("androidx.work:work-runtime:2.7.1")

// Kotlin用这个,支持协程。
implementation("androidx.work:work-runtime-ktx:2.7.1")

基本使用

创建Worker

Worker是负责处理任务的,在doWork()中进行耗时任务的处理,然后返回一个ResultResult可以是SuccessFailureRetry,其中SuccessFailure表示任务的执行情况,Retry表示需要重新执行一次doWork()WorkManager根据配置的策略过一段时间重新执行。

Worker

这是一个更新APP数据的Woker,在doWork进行逻辑处理。

kotlin 复制代码
class UpdateWork(appContext: Context, params: WorkerParameters) : Worker(appContext, params) {

    override fun doWork(): Result {
        return try {
            //更新APP数据
            updateAppData()
            //表示任务执行成功
            Result.success()
        } catch (e: IOException) {
            //重试,WorkManager根据配置的策略过一段时间重新执行
            Result.retry()
        } catch (e: Exception) {
            //表示任务执行失败
            Result.failure()
        }
    }

    private fun updateAppData() {
        //耗时操作
    }
}

CoroutineWorker

如果你想使用协程,可以继承CoroutineWorker。继承CoroutineWorker之后doWork将会是一个suspend方法,因此你可以使用协程进行任务处理。下面是一个例子。

kotlin 复制代码
class UpdateWork(appContext: Context, params: WorkerParameters) : CoroutineWorker(appContext, params) {

    override suspend fun doWork(): Result {

        return try {
          	//设置超时时间一分钟
            val success = withTimeout(1.minutes) {
              	//执行挂起函数
                updateAppData()
            }
          	//根据执行结果返回success或者failure
            if (success) Result.success() else Result.failure()
        } catch (e: TimeoutCancellationException) {
          	//一分钟内没执行完毕,重试。
            Result.retry()
        }
    }
		
  	//这是一个挂起函数
    private suspend fun updateAppData(): Boolean {
        //耗时操作
        delay(1000)
        return Random.nextInt(2) == 0
    }
    
}

创建WorkRequest

刚才创建了WorkerWorker是来执行任务的。但是什么时候执行,怎么样执行以及携带什么数据则是由WorkRequest来设置的,也就是说使用WorkRequest来制定Worker工作的条件和时机。下面介绍OneTimeWorkRequest一次性任务和PeriodicWorkRequest周期性任务。

OneTimeWorkRequest

顾名思义,这种工作请求是一次性的。我这里介绍一些常用的设置,下面给出示例代码并介绍。

kotlin 复制代码
val workRequest = OneTimeWorkRequestBuilder<UpdateWork>()
    .setConstraints(
        Constraints.Builder()
            .setRequiredNetworkType(NetworkType.UNMETERED)
            .setRequiresBatteryNotLow(true)
            .setRequiresCharging(true)
            .setRequiresDeviceIdle(true)
            .setRequiresStorageNotLow(true)
            .build()
    )
    .setInitialDelay(Duration.ofMinutes(1))
    .setBackoffCriteria(
        BackoffPolicy.LINEAR,
        Duration.ofMinutes(1)
    )
    .setInputData(
        workDataOf(
            UpdateWork.WORK_DATA_ID to "work data",
        )
    )
    .build()

Constraints

指定工作会在什么指定的条件下才执行,上面示例代码的含义如下。

  • setRequiredNetworkType:网络类型。
    • NOT_REQUIRED,不需要网络。
    • CONNECTED,网络连接的状态。
    • UNMETERED,Wi-Fi等不需要计费的网络。
    • NOT_ROAMING,非漫游网络。
    • METERED,计费网络
  • setRequiresBatteryNotLow :设置true的时候,Worker只有在非省电模式的时候运行。
  • setRequiresCharging :设置true的时候,Worker需要在充电状态才会运行。
  • setRequiresDeviceIdle:设置true的时候,Worker会在设备闲置的时候运行。如果你的任务逻辑是比较消耗性能的话,可以设置成true,这样的话不会影响用户在使用设备时候的体验。
  • setRequiresStorageNotLow:设置为true的话,Worker只会在存储空间充足的时候运行。

InitialDelay

Woker要执行doWork()前,进行一个特定的延迟时间,上面示例代码所设置的时间为1分钟。

BackoffCriteria

Worker返回Result.retry()的时候代表工作需要重新执行,那么就需要用这个方法来设置重试策略和时机。

  • 先说第二个参数,很明显,就是重试的延迟时间,我这里设置的是1分钟,可以设置的最低时间是10秒。

  • 第一个参数BackoffPolicy目前有两种。

    • LINEAR:线性的增加时间。第一次重试会在1分钟后执行,如果重试后还是失败则会延迟2分钟后执行,如果还是失败则3分钟以此类推。
    • EXPONENTIAL:指数的增加时间。第一次重试会在1分钟后执行,如果重试后还是失败则会延迟2分钟后执行,如果还是失败则4分钟以此类推。

InputData

用来传输数据,在这里设置后Worker可以使用inputData.getXXX()获取到这里传过去的数据

PeriodicWorkRequest

如果你想要执行周期性的任务,及时APP退出了也会执行,比如上传日志,更新配置等,可以使用PeriodicWorkRequest

kotlin 复制代码
//一个参数的构造方法
PeriodicWorkRequestBuilder<UpdateWork>(
    Duration.ofHours(1)//repeatInterval
).build()

//两个个参数的构造方法
PeriodicWorkRequestBuilder<UpdateWork>(
    Duration.ofHours(1),//repeatInterval
    Duration.ofMinutes(15)//flexTimeInterval
).build()

使用方法和刚才介绍的OneTimeWorkRequest一样也是可以设置各种执行条件和时机,不同的是PeriodicWorkRequestBuilder需要设置repeatInterval,另外一个参数flexTimeInterval是可选的,如果不设置则与repeatInterval一样。

repeatInterval

指定执行的周期,上面的代码设置的执行周期为一个小时。在这一个周期的什么时候执行是不确定的,但是能确保的是每一个执行周期内会执行一次。最小可以设置的值为15分钟。

flexTimeInterval

如果你想要你的任务执行的时机比较准确。换句话说,你想要每次任务执行的间隔都差不多,差不多每一小时执行一次。那么你可以设置flexTimeInterval。上面的代码中,flexTimeInterval设置的值为15分钟,也就是说,在每个时长为一小时的执行周期中,最后十五分钟才会执行你的任务。flexTimeInterval最小设置的值为5分钟。

添加WorkRequest

最后一步,就是添加WorkRequestWorkManager了。

这里介绍常用的两种添加类型

kotlin 复制代码
//添加WorkRequest到WorkManager
WorkManager.getInstance(this).enqueue(oneTimeWorkRequest)
//添加唯一的oneTimeWorkRequest到WorkManager
WorkManager.getInstance(this).enqueueUniqueWork(
    TAG,
    ExistingWorkPolicy.KEEP,
    oneTimeWorkRequest
)
//添加唯一的periodicWorkRequest到WorkManager
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
    TAG,
    ExistingPeriodicWorkPolicy.KEEP,
    periodicWorkRequest
)

enqueue

这个方法可以添加oneTimeWorkRequestperiodicWorkRequest,添加后WorkManager会根据WorkRequest所设置的条件执行WorkerdoWork()

enqueueUniqueWork

这个方法只添加oneTimeWorkRequest,一共有三个参数。

  • 第一个参数uniqueWorkName:可以认为是本次任务执行的id。
  • 第二个参数existingWorkPolicy:加入任务的时候WorkManager的还未执行的任务中存在了第一个参数的id,则会根据这个参数进行如下行为。
    • REPLACE:删除掉之前的任务,添加这一个。
    • KEEP:什么都不做,相当于这次的enqueue取消掉了。
    • APPEND:作为之前那个任务的子任务,前面执行成功后这个再执行。如果前面的任务执行失败或取消,这个任务也不会执行。
    • APPEND_OR_REPLACE:作为之前那个任务的子任务,无论前面的任务是否成功,这个任务也会执行。
  • 第三个参数work:添加的oneTimeWorkRequest

enqueueUniquePeriodicWork

enqueueUniqueWork 差不多,唯一的区别就是第二个参数existingWorkPolicy

PeriodicWorkexistingWorkPolicy只支持REPLACEKEEP

总结

  1. Worker是负责处理任务的。
  2. 使用WorkRequest来制定Worker工作的条件和时机。
  3. 调用WorkManagerenqueue方法添加任务到WorkManager里面,等待执行。

好了,到这里已经介绍的差不多了,大家有空可以试一下~

相关推荐
黄林晴2 小时前
如何判断手机是否是纯血鸿蒙系统
android
火柴就是我2 小时前
flutter 之真手势冲突处理
android·flutter
天花板之恋3 小时前
Compose之图片加载显示
android jetpack
法的空间3 小时前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
循环不息优化不止3 小时前
深入解析安卓 Handle 机制
android
恋猫de小郭3 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
jctech3 小时前
这才是2025年的插件化!ComboLite 2.0:为Compose开发者带来极致“爽”感
android·开源
用户2018792831673 小时前
为何Handler的postDelayed不适合精准定时任务?
android
叽哥3 小时前
Kotlin学习第 8 课:Kotlin 进阶特性:简化代码与提升效率
android·java·kotlin
Cui晨3 小时前
Android RecyclerView展示List<View> Adapter的数据源使用View
android