本文转载请联系Android开发编程公众号。前言WorkManager是Google提供的异步任务执行管理框架。它会根据手机的API版本和应用的状态选择合适的方式执行任务;当应用程序运行时,它会在应用程序进程中打开一个线程来执行任务。,退出应用时,WorkManager会根据设备的API版本选择合适的算法调用JobScheduler或者FirebaseJobDispatcher,或者AlarmManager来执行任务;今天我们就来介绍一下;一、WorkManager简介1、什么是WorkManager?WorkManager是一个API。允许您轻松安排可延迟的异步任务,这些任务即使在应用程序退出或设备重新启动时也应该运行。WorkManagerAPI是之前Android后台调度API的合适提议替代品,包括FirebaseJobDispatcher、GcmNetworkManager和JobScheduler。WorkManager将其前身的功能合并到新版本的一致API中,支持API级别14,同时保证电池寿命;WorkManager适用于可延迟的工作,即不需要立即运行但需要可靠运行的工作,即使用户退出或设备重启也不受影响。例如:向后端服务发送日志或分析数据定期与服务器同步应用数据;WorkManager不适合运行应用进程结束时可以安全终止的后台工作,也不适合需要立即执行的工作;2.优点兼容api14;可以对任务执行添加约束条件,比如延迟执行、是否在低功耗模式下执行、是否在充电模式下执行、是否在设备空闲时执行等;安排一次性或周期性的异步任务;监督任务,可以随时取消任务;链接任务,比如execution可以指定多个任务的执行顺序;确保任务执行,即使应用程序或设备重新启动;2.WorkManager使用1.添加依赖//根据项目需要自行添加依赖,不需要全部添加依赖{defwork_version="2.3.1"//(Javaonly)implementation"androidx.work:work-runtime:$work_version"//java语言选择这个//Kotlin+协程实现"androidx.work:work-runtime-ktx:$work_version"//kotlin选择这个}2.创建上传图片的后台任务:classUploadPicWork(privatevalcontext:Context,privatevalworkerParameters:WorkerParameters):Worker(context,workerParameters){overridefundoWork():Result{uploadPic()//上传图片的具体逻辑returnResult.success()}}2.1创建workrequest//这里的UploadPicWork是之前创建的taskvaluploadPicWork=OneTimeWorkRequestBuilder().setConstraints(triggerContentMaxDelay).build()2.2Executingtasks//这里的uploadPicWork就是上一步创建的workrequestWorkManager.getInstance(myContext).enqueue(uploadPicWork)3.复杂任务处理3.1为任务执行创建约束//注意以下条件都是&&关系valtriggerContentMaxDelay=Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED)//用到了连接网络时,避免各种网络判断,省时省力。setRequiresDeviceIdle(false)//是否在设备空闲时执行。setRequiresBatteryNotLow(true)//是否在电池电量低时执行。setRequiresStorageNotLow(true)//内存不足时是否执行.setRequiresCharging(true)//充电时是否执行.setTriggerContentMaxDelay(1000*1,TimeUnit.MILLISECONDS)//延迟执行.build()3.2给任务添加约束valuploadPicWork=OneTimeWorkRequestBuilder().setConstraints(triggerContentMaxDelay)//Constraints.build()WorkManager.getInstance(myContext).enqueue(uploadPicWork)//执行3.3传参worker//可以这样传参数valUploadPicWork=OneTimeWorkRequestBuilder()//这里setinputdata需要的参数是一个Data对象。请注意,它只能添加一次。如果有多个参数需要传递,可以封装成一个data数据类setInputData(workDataOf("params_tag"to"params")).setConstraints(triggerContentMaxDelay).build()3.4获取参数classUploadPicWork(privatevalcontext:Context,privatevalworkerParameters:WorkerParameters):Worker(context,workerParameters){overridefundoWork():Result{valparams=inputData.getString("params_tag")//获取传入的参数uploadPic()//上传图片returnResult.success()}}4.Worker的状态在doWork函数中,我们返回Result.success();我们默认,任务uploadPic函数执行成功,所以返回success状态,但是在实际开发过程中,可能由于各种问题会导致失败,此时无法返回success;Worker的各种状态表明,如果有前置任务没有完成,工作就处于BLOCKED状态;如果工作在满足约束和时序条件后可以立即运行,则认为处于ENQUEUED状态;当Worker主动执行时,处于RUNNING状态;如果Worker返回Result.success(),则认为处于SUCCEEDED状态,即终止状态;只有OneTimeWorkRequest才能进入这个状态A状态;如果Worker返回Result.failure(),则认为它处于FAILED状态。这也是一个终止状态;只有OneTimeWorkRequest可以进入这个状态。所有依赖的工作也被标记为FAILED,不会运行;当尚未终止的WorkRequest被取消时,它进入CANCELLED状态。所有依赖的工作也将被标记为CANCELLED并且不会运行;5.观察Worker的状态获取WorkInfo听说id获取,可以监听WorkManager.getWorkInfoById(UUID)或者WorkManager.getWorkInfoByIdLiveData(UUID)通过WorkRequest获取idWorkInfo;WorkManager.getInstance(this).getWorkInfoByIdLiveData(UploadPicWork.id)//通过id.observe(this,Observer{//it:WorkInfoit?.apply{when(this.state){WorkInfo.State.BLOCKED->println("BLOCKED")WorkInfo.State.CANCELLED->println("CANCELLED")WorkInfo.State.RUNNING->println("RUNNING")WorkInfo.State.ENQUEUED->println("ENQUEUED")WorkInfo.State.FAILED->println("FAILED")工作信息。State.SUCCEEDED->println("SUCCEEDED")else->println("elsestatus${this.state}")}}})可以通过tag获取,可以使用WorkManager.getWorkInfosByTag(String)或者WorkManager.getWorkInfosByTagLiveData(String)传递WorkRequest的WorkInfo对象;//要通过tag,需要设置tagvalUploadPicWork=OneTimeWorkRequestBuilder().setInputData(workDataOf("params_tag"to"params"))//传递参数.setConstraints(triggerContentMaxDelay)//设置constraints.addTag("tag")//设置tag.build()//获取workInfoWorkManager.getInstance(this).getWorkInfosByTagLiveData("tag").observe(this,Observer{it:List//这里是一个集合,作为示例代码,默认只有0indexit?.apply{when(this[0].state){WorkInfo.State.BLOCKED->println("BLOCKED")WorkInfo.State.CANCELLED->println("CANCELLED")WorkInfo.State.RUNNING->println("RUNNING")WorkInfo.State.ENQUEUED->println("ENQUEUED")WorkInfo.State.FAILED->println("FAILED")WorkInfo.State.SUCCEEDED->println("SUCCEEDED")else->println("elsestatus${this[0]}")}}})6.多重顺序执行Workers您可以使用WorkManager来创建和排队工作链。工作链用于指定多个关联任务并定义这些任务的运行顺序。当您需要以特定顺序运行多个任务时,这尤其有用;6.1顺序执行单个任务例如有三个任务workA,workB,workC,执行顺序只能是workA---->workB--->workC,可以按如下方式处理;WorkManager.getInstance().beginWith(workA).then(workB)instance.then(workC).enqueue();上面的workA、workB、workC都是WorkRequest的子类实现对象。WorkManager会按照上面的顺序依次执行workA、workB、workC,但是如果这三个任务在执行过程中有一个失败了,整个执行就会结束。并返回Result.failure()6.2顺序执行多个任务有时可能需要先执行一组任务,然后再执行下一组任务,可以通过以下方式完成。WorkManager.getInstance()//首先,运行所有任务(并行):.beginWith(Arrays.asList(workA1,workA2,workA3))//...当所有任务完成后,运行单个任务:.then(workB)//...然后运行Ctasks(以任意顺序):.then(Arrays.asList(workC1,workC2)).enqueue();7、执行重复任务就是在给定的时间间隔内有规律地执行任务,例如每小时上报一次位置信息,每3小时备份一次日志等;这个时间间隔不应低于15分钟;valtriggerContentMaxDelay=Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED)//.setRequiresDeviceIdle(false).setRequiresBatteryNotLow(true).setRequiresStorageNotLow(true).setRequiresCharging(true).setTriggerContentMaxDelay(1000*1,TimeUnit.MILLISECONDS).build()//valUploadPicWork=//OneTimeWorkRequestBuilder()//.setInputData(workDataOf("params_tag"to"params"))//.setConstraints(triggerContentMaxDelay)//.addTag("tag")//.build()//valbuild=PeriodicWorkRequestBuilder(1000*60*15,TimeUnit.MICROSECONDS).setConstraints(triggerContentMaxDelay).build()WorkMmanager.getInstance(this).enqueue(build)8.取消任务执行可以通过任务的ID获取任务来取消任务。任务ID可以从WorkRequest中获取;cancelAllWork():取消所有任务;cancelAllWorkByTag(Stringtag):取消一个标签相同的Group任务;cancelUniqueWork(StringuniqueWorkName):取消唯一任务;UUIDcompressionWorkId=compressionWork.getId();WorkManager.getInstance().cancelWorkById(compressionWorkId);注意并不是所有的任务都可以取消,当任务在执行的时候是不能取消的。当然,任务执行完毕,取消也是有意义的。也就是说只有当任务加入到ManagerWork队列但还未执行??时才能取消;9、使用WorkManager时遇到的问题9.1使用PeriodicWorkRequest只执行一次,不执行WorkManagerinstance=newPeriodicWorkRequest.Builder(PollingWorker.class,10,TimeUnit.MINUTES).build();原因:PeriodicWorkRequest默认的时间间隔是15分钟。如果设置的时间小于15分钟,就会出现问题;解决方法:设置的默认时间必须大于等于15分钟。另外需要注意的是,即使设置时间为15分钟,也不一定每隔15分钟执行一次;9.2在doWork()方法中更新UI导致崩溃:doWork()方法是在WorkManager管理的后台线程中执行的,更新UI的操作只能在主线程中汇总。在这个物欲横流的社会,让我们一起学习,互相鼓励