首页 > 其他分享 >Android WorkManager 初探

Android WorkManager 初探

时间:2023-11-27 22:31:42浏览次数:36  
标签:Work WorkManager 17128 cleanWork 初探 path Android Data

前言

总结和学习 Android WorkManager 的相关用法。

WorkManager 有什么特殊之处

在日常开发中,有些任务需要在异步线程执行,并且这些工作耗时较长,通过普通的子线程或后台服务无法胜任时,就需要 WorkManager 了。

WorkManager 适用于需要可靠运行的工作,即使用户导航离开屏幕、退出应用或重启设备也不影响工作的执行。例如:

  • 向后端服务发送日志或分析数据。
  • 定期将应用数据与服务器同步。 WorkManager 不适用于那些可在应用进程结束时安全终止的进程内后台工作。

它也并非对所有需要立即执行的工作都适用的通用解决方案

可靠运行 这个特点太有诱惑力了,尤其是对于周期性的工作。相比通过诸如1像素的 Activity、进程保活、互相保活/拉起之类的方式来执行特定的工作,使用官方提供的 WorkManager 可以避免做一些非常 hack 的工作,正所谓事半功倍。

WorkManager 的功能

相比传统的 AsyncTask/Coroutine/RxJava/Executors ,WorkManager 有更鲜明的特点。

  • 结合系统特性的约束: 可以结合设备当前的网络、电量等状况,约束任务执行的条件。比如等到用户连接 WiFi 后进行 App 的更新,电量充足的时候进行系统更新,条件不满足就等待,都可以通过 WorkManager 内置的 API 非常方便的实现。
  • 强大的调度: 通过 WorkManager 执行的工作,会由系统通过 SQLite 数据库进行管理,而上层开发者可以基于工作的标记进行状态监控、取消等操作。
  • 工作链和灵活的重试策略: 这一点熟练使用 RxJava 的同学应该非常喜欢。将多个工作通过合理的编排进行串联并联,根据工作执行的结果进行重试,WorkManager 都支持。

同时 WorkManager 可以与 Coroutine 及 RxJava 无缝衔接。

这里需要明白的是,WorkManager 不是用来替代 Coroutine 或其他可以执行异步操作框架的,而是基于这些框架的特点提供了更强大的功能,是互补的关系,一些通过 Coroutine 就可以完成的工作,就不要强行往 WorkManager 上套了,不要为了用而用,很多时候合适就足够了。

WorkManager 入门

关于使用 WorkManager 如何添加依赖及 demo 级别的的使用场景,可以直接参考 WorkManager 使用入门,非常简单。

Android WorkManager 初探_Data

从官方提供的工作类型,可以看到主要有两类工作,即一次性和周期性的,顾名思义一个是执行一次就完事,一类是周期性重复执行的工作。

下面就通过一个简单的示例,从一次性工作(在 WorkManager 中,可以多执行多个任务,规范期间一个任务被定义为一个 Work,这里索性就称为工作)开始,了解一下具体如何使用 WorkManager.

  1. 定义目标

一个删除文件的任务,连续多次调用,覆盖执行。删除任务执行时,传入的路劲参数异常或文件不存在时返回失败,正常删除则返回成功。

  1. 创建 Work
class CleanWork(appContext: Context, workerParameters: WorkerParameters) :
        Worker(appContext, workerParameters) {
        override fun doWork(): Result {
            val path = inputData.getString("path")
            return if (TextUtils.isEmpty(path)) {
                Result.failure(Data.Builder().putString("result", "filepath is null").build())
            } else {
                if (cleanOutDateFile(path!!)) {
                    Result.success()
                } else {
                    Result.failure(Data.Builder().putString("result", "file not exist").build())
                }
            }
        }
    }

这里关注以下几点 :

  • 继承抽象类 Worker 定义自己的 Worker ,实现 doWork 方法。
  • 返回参数 Result 有三个类型
  • Result.success():工作成功完成。
  • Result.failure():工作失败。
  • Result.retry():工作失败,应根据其重试政策在其他时间尝试。
  • Work 入参和结果的传递
  • 通过 inputData 的 getXXX 方法,可以获取调用任务时传入的参数
  • 通过 Result 返回结果是参入的 Data 参数,可以返回具体的结果,不传的话,就相当于 void 类型的函数。

简单看一下 cleanOutDateFile 的定义

private fun cleanOutDateFile(path: String): Boolean {
        val file = File(path)
        return if (file.exists()) {
            file.delete()
            true
        } else {
            false
        }
    }
  1. 创建 WorkRequest 并加入队列
fun clean(context: Context, path: String) {
        val request =
            OneTimeWorkRequestBuilder<CleanWork>()
                .addTag("cleanWork")
                .setInputData(workDataOf("path" to path)).build()

        WorkManager.getInstance(context)
            .enqueueUniqueWork("clean", ExistingWorkPolicy.REPLACE, request)
    }

这里关注以下几点 :

  • OneTimeWorkRequestBuilder 的泛型参数就是上面自定义的 Work
  • 通过 addTag 可以给当前要执行的 Work 添加唯一标识,这样可以基于这个 tag 获取 Work 执行的结果,或者取消 Work
  • setInputData 传入 Data 对象,即可给 Work 传参,这里的参数类型其实就是 Map,因此可以传递各种类型的值,确保 key 和 Work 中对应即可。
  • WorkRequest 加入队列时,可以简单调用 enqueue 方法,这样如果有重复的 WorkRequest 发生冲突,默认会采取保留现有 Work ,抛弃新 WorkRequest 。或者像这里一样调用 enqueueUniqueWork,通过定义 tag ,自行制定面对冲突情况的策略。
  1. 调用并观察 Work 执行情况
class WorkManagerViewModel(app: Application) : AndroidViewModel(app) {
    private val workManager = WorkManager.getInstance(app)

    val cleanWorkInfo = workManager.getWorkInfosByTagLiveData("cleanWork")
}


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        workManagerViewModel.cleanWorkInfo.observe(this@FilterActivity) {
            Log.i("cleanWork", "info -> $it")
            if (it != null && it.size > 0) {
                val work = it[it.size - 1]
                Log.i("cleanWork", "$work")
            val out = work.outputData.getString("result")
                Log.i("cleanWork", "$out")               
            }
        }


        val path = cacheDir.absolutePath + File.separator + "current.txt"
        WorkUtil.clean(it.context, path)

    }

这里连续调用两次 clean 方法之后看日志


20:23:16.391 17128-17128 cleanWork                           I  info -> [WorkInfo{mId='d64379e8-17b5-484d-9c2f-2273c1fd629f', mState=SUCCEEDED, mOutputData=Data
                                                                                                    {}, mTags=[cleanWork, com.engineer.android.mini.jetpack.work.WorkUtil$CleanWork], mProgress=Data {}}]
20:23:16.391 17128-17128 cleanWork                           I  WorkInfo{mId='d64379e8-17b5-484d-9c2f-2273c1fd629f', mState=SUCCEEDED, mOutputData=Data
                                                                                                    {}, mTags=[cleanWork, com.engineer.android.mini.jetpack.work.WorkUtil$CleanWork], mProgress=Data {}}
20:23:16.391 17128-17128 cleanWork                           I  null
20:25:07.611 17128-17128 cleanWork                           I  info -> [WorkInfo{mId='b238f68c-b1c8-4994-975b-7f5d2b67d10c', mState=FAILED, mOutputData=Data {result : file not
                                                                                                    exist, }, mTags=[cleanWork, com.engineer.android.mini.jetpack.work.WorkUtil$CleanWork], mProgress=Data {}}]
20:25:07.611 17128-17128 cleanWork                           I  WorkInfo{mId='b238f68c-b1c8-4994-975b-7f5d2b67d10c', mState=FAILED, mOutputData=Data {result : file not
                                                                                                    exist, }, mTags=[cleanWork, com.engineer.android.mini.jetpack.work.WorkUtil$CleanWork], mProgress=Data {}}
20:25:07.611 17128-17128 cleanWork                           I  file not exist

可以看到,第一次执行成功后,再次进行 clean 操作时就返回了 file not exist 的错误信息,而整个队列里也只有一条 WorkInfo,说明设置的 ExistingWorkPolicy.REPLACE 的策略也生效了。

这里通过这个简单的示例可以看到,WorkManager 非常强大,而且其 API 的定义非常友好,参数和方法命名很恰当,通过名称就可以知道要方法或参数的含义。

小结

WorkManager 最大的特点是其执行的是持久化的任务。这点我们通过 Android Studio Inspection 功能就可以看到,他通过 SQLite 数据库从不同维度存储了各种插入到队列中 Worker 的信息。

Android WorkManager 初探_RxJava_02

因此,在定义 Worker ,创建 WorkRequest 和选择 Worker 添加到队列中的方式是都要谨慎,因为这些信息都会被存储。同时,我们也可以通过 Inspection 工具查看当前进程中存在的 Worker 信息,进行问题的排查和了解。


标签:Work,WorkManager,17128,cleanWork,初探,path,Android,Data
From: https://blog.51cto.com/u_16175630/8589258

相关文章

  • Android Compose 使用Pager (with TabRow)
    Pager基本内容看官方吧:AndroidCompose中的分页器不同页显示不同内容错误示范@ComposableHorizontalPager(state=pagerState,modifier.fillMaxHeight(),beyondBoundsPageCount=2,verticalAlignment=Alignment.Top){if(pagerState.currentPage==0){//使......
  • 2048 ,Android 休闲益智游戏开发
    A.项目描述《2048》是一款经典的益智小游戏,它的目标是通过合并相同数字来达到2048这个最高分。该游戏规则简单,玩家需要通过滑动屏幕来移动方块,相同数字的方块会合并成一个新的数字方块。这样的简单操作让人可以轻松上手。《2048》小游戏app的技术原理主要涉及游戏逻辑、用户界面和......
  • 轻松实现海报换脸!相芯SDK海报换脸功能的简单集成方法(Android)
    相芯SDK的海报换脸功能是一种面部合成技术,允许用户将自己的脸部特征与指定的海报或图片进行合成,实现换脸的效果。该功能可以用于各种娱乐应用、社交媒体、相机应用和虚拟试妆等场景。1.功能介绍逼真和自然的换脸效果:相芯SDK使用先进的人脸识别和图像合成技术,确保换脸效果的逼真和......
  • Android对重启原因的记录
    事后log中,可以在prop.txt中获取到他们:./prop.txt:259:[persist.sys.boot.reason]:[]./prop.txt:260:[persist.sys.boot.reason.history]:[kernel_panic,bug,52663./prop.txt:789:[sys.boot.reason]:[kernel_panic,bug]./prop.txt:790:[sys.boot.reason.last]:[kernel_p......
  • Android 模拟器横向视图
    HowtochangeAndroidemulatortolandscapemode?ctrl + fn + F11 on Mac to change the landscape to portrait and vice versa.left-ctrl + F11 on Windows 7.ctrl + F11 on Linux.......
  • Android Intent打开指定网页【问题与方法】
    方法一.Intentintent; PackageManagerpackageMgr=getPackageManager(); intent=packageMgr.getLaunchIntentForPackage("com.android.chrome");intent.setPackage(null); intent.setAction(Intent.ACTION_VIEW); intent.addCategory(......
  • Android Studio XML文件没有提示
    长路漫漫唯剑作伴原因:项目从AS3.5.2转到AS4.2.2后出现xml文件没有提示。解决:1.build:gradle:3.5.2换成最新的build:gradle:4.2.22.gradle-wrapper.properties由gradle-5.4.1-all.zip换成4.2.2最低要求版本gradle-6.7.1-all.zip项目下载构建完成即可......
  • Android学习 第三&四周
    主要内容1在AndroidStudio中配置了Copilot2学习了Android中权限的相关知识,学会了在布局中声明权限,在程序中动态申请权限的方法3完成了一个简易的本地视频播放器的demo,可以扫描本地的视频形成列表,并可以播放。......
  • Android平台GB28181设备接入模块开发填坑指南
    技术背景为什么要开发Android平台GB28181设备接入模块?这个问题不再赘述,在做Android平台GB28181客户端的时候,媒体数据这块,我们已经有了很好的积累,因为在此之前,我们就开发了非常成熟的RTMP推送、轻量级RTSP服务、录像模块、针对音视频的对接处理单元。这让我们在做Android平台GB28181......
  • 阿里内部流出最新的Android中高级面试题,赶紧看,晚了怕没了
    前言2023是最不平凡的一年,可能找工作的程序员在前半年感触不是很深,尤其是从铜三铁四之后,找工作是越来越难了,投出去的简历都是已读不回。其实,伴随着互联网行业寒冬的到来,各大企业都不敢大肆招聘,都是选择收缩发展,加上程序员内部越来越卷,要求越来越高了,要想在IT行业继续发展进阶拿高......