Android Jetpack - 后台处理

it2024-03-27  73

WorkManage:调度即使在应用退出或设备重启时仍应运行的可延迟异步任务,适用于可延时并且需要保证一定完成的工作。 简单使用: 1.引入依赖 def work_version = “2.3.4” implementation “androidx.work:work-runtime: w o r k v e r s i o n " / / 如 果 是 k o t l i n / / i m p l e m e n t a t i o n " a n d r o i d x . w o r k : w o r k − r u n t i m e − k t x : work_version" //如果是kotlin //implementation "androidx.work:work-runtime-ktx: workversion"//kotlin//implementation"androidx.work:workruntimektx:work_version” 2.编写需要的Worker //需要运行的工作继承类Worker public class LogWorker extends Worker { private static final String LOG_TAG = LogWorker.class.getSimpleName(); public LogWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); } @NonNull @Override public Result doWork() { //这里做想要的工作 Log.d(LOG_TAG, “LogWorker doWork”); //返回工作完成 return Result.success(); } //外部启动这项任务 public static void startOnesLogWorker(Context context){ //创建单次执行的worker OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(LogWorker.class).build(); //将这项工作交给系统,由系统去执行,队列里面任务(还在等待调度 未执行的那种)不能超过100个,不然会crash,这是workmanager代码的限制 WorkManager.getInstance(context).enqueue(oneTimeWorkRequest); } //创建周期工作 public static void startPeriodicLogWorker(Context context){ //周期性工作,每小时一次 PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(LogWorker.class, 1, TimeUnit.HOURS).build(); WorkManager.getInstance(context).enqueue(periodicWorkRequest); } } 3.外部调用 LogWorker.startOnesLogWorker(getApplicationContext()); 这时可以看到日志打印 D/LogWorker: LogWorker doWork I/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=bc9bd60e-a4b7-47df-bd61-39c988bc50b1, tags={ com.dean.smartapp.worker.LogWorker } ]

给工作添加运行条件 可以为工作设置Constraints,在Constraints 中约束工作进行的条件,如充电时,设备空闲时等。 具体使用: //这边约束了工作应仅在设备空闲且接通电源时运行 Constraints constraints = new Constraints.Builder().setRequiresDeviceIdle(true).setRequiresCharging(true).build(); OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(LogWorker.class).setConstraints(constraints).build(); 具体约束 setRequiredNetworkType(NetworkType networkType) 设置网络状态约束,NetworkType 取值有NOT_REQUIRED(无需网络)、CONNECTED(网络连接时,不指定啥网络)、UNMETERED(不计流量网络,即WIFI)、NOT_ROAMING(非漫游网络)、METERED(流量网络) setRequiresBatteryNotLow(boolean requiresBatteryNotLow) 设置是否在低电量执行, true 在电量充足时执行 >15% setRequiresCharging(boolean requiresCharging) 设置是否在充电时执行, true 在充电时执行 setRequiresDeviceIdle(boolean requiresDeviceIdle) 设置是否在设备空闲时执行, true 在空闲时执行,比如息屏,cpu利用率不高 setRequiresStorageNotLow(boolean requiresStorageNotLow) 设置是否在低可用存储时执行 true 在存储空间充足时执行 > 15% setTriggerContentMaxDelay(Duration duration) setTriggerContentMaxDelay(long duration, TimeUnit timeUnit) setTriggerContentUpdateDelay(long duration, TimeUnit timeUnit) setTriggerContentUpdateDelay(Duration duration) 这四个都是设置uri变化到任务执行可接受的最大延迟时间(都没用过,解释怕说错了误导) 给工作设置初始延迟 工作任务加入队列后,如果条件都满足则会立即执行,此时想要延迟执行可以通过setInitialDelay指定 //设置10分钟后执行 OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(LogWorker.class).setInitialDelay(10, TimeUnit.MINUTES).build(); 给工作设置重试和退避政策 在doWork方法中可以在一定条件下返回Result.retry()来告诉系统这项工作还未完成需要重试。 这时系统会根据自身的退避延迟时间和政策重新调度该工作,退避延迟时间指的是系统接收到需要重试的工作到真正执行的时间,政策指这个时间如何变化,是线性的还是指数的还是其他。这个退避延迟时间和政策都可以通过setBackoffCriteria自定义 OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(LogWorker.class).setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 100, TimeUnit.MILLISECONDS).build(); BackoffPolicy指定政策:EXPONENTIAL 让延迟时间指数增长、LINEAR 让延迟时间线性增长 第二个参数是时间 第三个参数是时间类型,这边给的是毫秒数 工作的输入和输出 输入:通过setInputData来设置输出 Data imageData = new Data.Builder().putString(Constants.KEY_IMAGE_URI, imageUriString).build(); OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadWorker.class).setInputData(imageData).build(); //在dowork中根据key取出相应的值 String imageUriInput = getInputData().getString(Constants.KEY_IMAGE_URI); 输出:在dowork中返回值 Data outputData = new Data.Builder.putString(Constants.KEY_IMAGE_URL, response.imageUrl).build(); //具体接收使用,后面会有 return Result.success(outputData); 给工作贴上标签 可以.addTag("")给工作贴上一个标签,后续可以对同一种标签的工作执行统一操作 OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(LogWorker.class).addTag("log").build(); 工作信息 工作的信息保存在类WorkInfo里面:包括工作的状态、id、标签和输出数据 状态信息WorkInfo.State 工作状态有:BLOCKED(有尚未完成的前提性工作,比如等待前面工作完成)、ENQUEUED(工作能够在满足 Constraints 和时机条件后立即运行)、RUNNING(工作在执行中)、SUCCEEDED和FAILED(工作完成和失败,只有单次工作OneTimeWorkRequest可以进入)、CANCELLED(取消) 获取WorkInfo方式:获取方式主要有四种 1.通过ID:WorkManager.getWorkInfoById(UUID) 和 WorkManager.getWorkInfoByIdLiveData(UUID) 2.通过TAG:WorkManager.getWorkInfosByTag(String) 和 WorkManager.getWorkInfosByTagLiveData(String) 3.通过名称:WorkManager.getWorkInfosForUniqueWork(String) 和 WorkManager.getWorkInfosForUniqueWorkLiveData(String) 4.获取所有:WorkContinuation.getWorkInfos() 和 WorkContinuation.getWorkInfosLiveData() WorkContinuation是工作链,能够执行一系列工作,后面会有具体介绍 每个不带LiveData的方法就是直接获取WorkInfo,带LiveData的是可以观察 WorkInfo 的变化,例如将完成后的信息展示给用户。 这边以WorkContinuation.getWorkInfosLiveData()举例 //创建WorkContinuation,通过beginWith设置进行的工作 WorkContinuation workContinuation = WorkManager.getInstance(this).beginWith(LogWorker.getOnesLogWorkerRequest()); //将工作放入队列中 workContinuation.enqueue(); //获取可观察的workInfo,用来接收dowork返回的数据,当workInfo发送变化时会自动触发 workContinuation.getWorkInfosLiveData().observe(this, new Observer<List<WorkInfo>>() { @Override public void onChanged(List<WorkInfo> workInfos) { for (WorkInfo workInfo : workInfos) { UUID id = workInfo.getId(); WorkInfo.State state = workInfo.getState(); if (id.equals("LOG_ID") && state == WorkInfo.State.SUCCEEDED){ Data outputData = workInfo.getOutputData(); mtvTitle.setText(outputData.getString("log_output_data_key")); } } } }); 获取工作进度:这边和输出值 流程上一样,只是发送和接收方式不同 首先它们都需要一个data,Data progressData = new Data.Builder().putInt(key值, value值当前进度,这个在dowork中根据自己的任务计算进度).build() 进度的发送方式是setProgressAsync(progressData); 进度的接收方式是Data data = workinfo.getProgress(); data.getInt(key值) 具体代码: //work中发送当前进度 public Result doWork() { for (int i = 0; i < 100; i++){ Data progressData = new Data.Builder().putInt(“PROGRESS”, i).build(); setProgressAsync(progressData); } return Result.success(); } //界面中显示 WorkManager.getInstance(getApplicationContext()).getWorkInfoByIdLiveData(requestId) .observe(lifecycleOwner, new Observer<WorkInfo>() { @Override public void onChanged(@Nullable WorkInfo workInfo) { if (workInfo != null) { Data progress = workInfo.getProgress(); int value = progress.getInt(“PROGRESS”, 0) // Do something with progress } } }); 工作链 WorkContinuation 指定多个关联任务并定义这些任务的运行顺序 具体使用: //以一个单项工作开始 WorkContinuation workContinuation = WorkManager.beginWith(OneTimeWorkRequest); //以一组工作开始,这些工作可能并行执行 WorkContinuation workContinuation = WorkManager.beginWith(List<OneTimeWorkRequest>); //后续添加工作 workContinuation.then(OneTimeWorkRequest).then(OneTimeWorkRequest); //开始放到系统队列中等待执行 workContinuation.enqueue(); 注:1.当使用then时,上一个任务的输出将作为下一个任务的输入,输出和输入方式不变,但是需要注意值覆盖问题,这边可以给request设置值冲突模式,即要返回的值的key已经存在时解决方案,使用setInputMerger方法 //setInputMerger有两种值 ArrayCreatingInputMerger.class:尝试合并冲突,用数组返回 OverwritingInputMerger.class覆盖 OneTimeWorkRequest compress = new OneTimeWorkRequest.Builder(CompressWorker.class).setInputMerger(ArrayCreatingInputMerger.class).build(); 2.当使用then时,后续工作受前面工作影响,前面工作都SUCCESS,后面工作才执行,如果前面有工作被取消或者失败,后面工作也是相同的状态 唯一工作 之前一直使用WorkManager.getInstance(context).enqueue(OneTimeWorkRequest)来创建一项工作 其实还可以通过WorkManager.getInstance(context).enqueue(List<OneTimeWorkRequest>)来创建一组工作 使用WorkContinuation来创建一条链工作 这些添加的时候无法避免一个问题,当队列中已经存在时的情况,因为大部分情况是不需要重复添加的,这时就可以设置添加重复工作时的处理方式 按照先前顺序分别对应 WorkManager.getInstance(context).enqueueUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest) WorkManager.getInstance(context).enqueueUniqueWork(String, ExistingWorkPolicy, List<OneTimeWorkRequest>) WorkManager.getInstance(context).enqueueUniquePeriodicWork(String, ExistingPeriodicWorkPolicy, PeriodicWorkRequest) WorkManager.getInstance(context).beginUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest) 第一个参数String,唯一名称 - 用来标识 WorkRequest 的键,后面如果重复添加就使用这个键处理 第二个参数ExistingWorkPolicy,它标识重复任务的执行方式,有三种 REPLACE :删除已有任务,添加新任务 KEEP :忽略本次操作,不影响现有任务执行 APPEND :放到当前序列末尾,APPEND 与 PeriodicWorkRequest 无法一起使用,如果是PeriodicWorkRequest可在每次添加前删除一下

前台服务:对于需要立即运行并且必须执行完毕的由用户发起的工作 AlarmManager:在确切的时间运行某项作业

DownloadManager:应用执行长时间运行的 HTTP 下载,在下载失败或连接发生更改以及系统重新启动后重新尝试下载。

最新回复(0)