专业的编程技术博客社区

网站首页 > 博客文章 正文

Android中Service的替代品--WorkManager

baijin 2024-09-06 14:53:10 博客文章 4 ℃ 0 评论

在Android中,一般我们写一个需要后台执行的任务时,比如网络请求,蓝牙操作等,都会使用Service。但现在WorkManager有逐渐替代Service的趋势,一方面WorkManager有其独特优势,再一个Service写起来确实麻烦些。

WorkManager概述

WorkManager大概有以下几个优点:

  • 可靠性:保证任务最终会被执行,即使应用退出或设备重启。
  • 电池效率:自动选择最佳的时间和方式来运行任务,以减少对电池的影响。
  • 简洁性:相比传统的后台服务,提供了更简单的 API。
  • 灵活性:支持一次性任务和周期性任务,以及任务间的依赖关系。
  • 适应性:可以设置任务的约束条件,如网络连接、充电状态等。
  • 兼容性好:可以在所有版本的 Android 上正常工作。

也就是说,WorkManager能更好适应手机环境,兼具效率基础上最大限度保证任务可靠执行。当然,凡事有两面性,提高效率和可靠性的代价就是即时性可能会受点影响,WorkManager的缺点总结如下:

  • 延迟执行:可能不如直接启动服务或线程来得即时。
  • 学习曲线:对于习惯了传统服务的开发者来说,可能需要时间适应。
  • 功能限制:不能实时监听任务进度或结果,只能监听任务状态变化。
  • 性能:可能会增加应用程序的内存和 CPU 占用。
  • 电池消耗:频繁执行后台任务可能会导致电池消耗增加。
  • 资源调度:不能保证任务会在特定时间内开始执行。

我们需要根据使用场景来合理判断,一般来说,WorkManager可以应用在以下场景:

  • 数据同步:定期将本地数据与服务器进行同步。
  • 定时任务:例如定时清理缓存等。
  • 后台上传下载:例如下载应用更新、下载图片等。
  • 报告统计:定时发送统计数据至服务器。
  • 通知推送:在特定时间发送本地或远程通知

WorkManager的集成使用

我们以网络请求为例,简单看下WorkManager的使用。

首先我们项目使用了Jetpack Compose框架,以依赖注入的方式操作WorkManager实例。

class SyncWorkerManager @Inject constructor(
    @ApplicationContext private val context: Context,
) {
    private val SYNC_WORK_NAME = "SyncWorkerName";

    fun sync() {
        val workManager = WorkManager.getInstance(context)
        workManager.enqueueUniqueWork(
            SYNC_WORK_NAME,
            ExistingWorkPolicy.KEEP,
            SyncWorker.workRequest()
        )
    }

}

这里我们定义了同步网络数据的接口,这个接口实际就是启动一个Worker,下面来看一下Worker的具体代码

@HiltWorker
class SyncWorker @AssistedInject constructor(
    @Assisted private val appContext: Context,
    @Assisted workerParams: WorkerParameters,
    private val networkRepository: NetworkRepository,
    private val dataRepository: DataRepository
) : CoroutineWorker(appContext, workerParams) {

    @SuppressLint("MissingPermission")
    override suspend fun doWork(): Result = withContext(IO) {
        val dataList = networkRepository.getData()
        val dataListIds = dataList.map { it.id }
        if (dataList.isNotEmpty()) {
            // merge
            val dataDB = dataRepository.getDataList()
            val dataDBIds = dataDB.map { it.uid }
            val toIgnore = dataListIds.intersect(dataDBIds)
            val toAdd = dataListIds.subtract(dataDBIds)
            val toDelete = dataDBIds.subtract(dataListIds)
            if (toAdd.isNotEmpty()) {
                dataRepository.add(dataList.filter { toAdd.contains(it.id) }.map { it.toDataDB() })
            }
            if (toDelete.isNotEmpty()) {
                dataRepository.delete(toDelete)
            }
        }
        Result.success()
    }

    companion object {
        fun workRequest() = OneTimeWorkRequestBuilder<SyncWorker>()
            .build()
    }
}

这里的代码也很好理解,就是做一个网络请求,然后和本地数据库room里的数据进行merge。可以说是十分常见的一个使用场景了。

调用的话,SyncWorkerManager可以在viewModel中直接引入,封装出接口进行调用,像下面代码片段这样

@HiltViewModel
class MyViewModel @Inject constructor(
    val myRepository: MyRepository,
    val syncWorkerManager: SyncWorkerManager
) : ViewModel() {

    fun sync() {
      syncWorkerManager.sync()
    }

}

以上就是WorkManager的使用,还是很简单方便的,如果有替代Service的想法,不妨尝试一下。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表