一、介绍
Jetpack?
我们经常看到,似乎很高端,其实这个就是一个名词,或者说是一种框架概念。
Jetpack 包含一系列 Android 库,它们都采用最佳做法并在 Android 应用中提供向后兼容性。
Jetpack 应用架构指南概述了构建 Android 应用时要考虑的最佳做法和推荐架构。
最终就是Android平台的一个介绍,有些新人看到又以为是什么平台,甚至一些招聘会写需要了解Room数据,Jetpack组件,其实我们现在好多已在使用了,但是非专业人会不停提jetpack导致一些人在理解的时候被吓到了。
JetPack组件已全部支出androidX,如果你的项目没有升级到AndroidX,请先升级到AdnroidX。
利用 Jetpack
Jetpack 库可以单独使用,也可以组合使用,以满足应用的不同需求。
- WorkManager - 满足您的后台调度需求。
- Room - 实现数据存储持久性。
- Navigation - 管理应用导航流程。
- CameraX - 满足相机应用需求。
- 请参阅所有 Jetpack 库的概览。
二、WorkManager
WorkManager 是适合用于持久性工作的推荐解决方案。如果工作始终要通过应用重启和系统重新启动来调度,便是持久性的工作。由于大多数后台处理操作都是通过持久性工作完成的,因此 WorkManager 是适用于后台处理操作的主要推荐 API。
持久性工作的类型
WorkManager 可处理三种类型的持久性工作:
- 立即执行:必须立即开始且很快就完成的任务,可以加急。
- 长时间运行:运行时间可能较长(有可能超过 10 分钟)的任务。
- 可延期执行:延期开始并且可以定期运行的预定任务。
类型 | 周期 | 使用方式 |
---|---|---|
立即 | 一次性 | OneTimeWorkRequest 和 Worker 。 如需处理加急工作,请对 OneTimeWorkRequest 调用 |
长期运行 | 一次性或定期 | 任意 WorkRequest 或 Worker 。在工作器中调用 setForeground() 来处理通知。 |
可延期 | 一次性或定期 | PeriodicWorkRequest 和 Worker 。 |
使用 WorkManager 保证工作可靠性
WorkManager 适用于需要可靠运行的工作,即使用户导航离开屏幕、退出应用或重启设备也不影响工作的执行。例如:
- 向后端服务发送日志或分析数据。
- 定期将应用数据与服务器同步。
WorkManager 不适用于那些可在应用进程结束时安全终止的进程内后台工作。它也并非对所有需要立即执行的工作都适用的通用解决方
三、接入
1、依赖库
//work def work_version = "2.7.1" // (Java only) implementation("androidx.work:work-runtime:$work_version") // Kotlin + coroutines implementation("androidx.work:work-runtime-ktx:$work_version") // optional - RxJava2 support implementation("androidx.work:work-rxjava2:$work_version") // optional - GCMNetworkManager support implementation("androidx.work:work-gcm:$work_version") // optional - Multiprocess support implementation "androidx.work:work-multiprocess:$work_version"
由于国内应用,GCM可以不需要,因为这个GCM是google service,国内的手机不支持
2、接入
2.1 先定义一个worker
工作使用 Worker
类定义。doWork()
方法在 WorkManager 提供的后台线程上异步运行
class MyWorks(context: Context,workerParameters: WorkerParameters) : Worker(context, workerParameters) {
@SuppressLint("RestrictedApi")
override fun doWork(): Result {
//后台异步执行
var success=Result.Success()
var error=Result.failure()
var retry=Result.retry()
return success
}
}
doWokr():是我们需要执行的方法体,需要异步执行,都将在这边执行。最后将执行的结果返回即可Result。
从 doWork()
返回的 Result
会通知 WorkManager 服务工作是否成功,以及工作失败时是否应重试工作。
Result.success()
:工作成功完成。Result.failure()
:工作失败。Result.retry()
:工作失败,应根据其重试在其他时间尝试。
public Success(@NonNull Data outputData) { super(); mOutputData = outputData; }
创建 WorkRequest
定义工作后,必须使用 WorkManager 服务进行调度该工作才能运行。对于如何调度工作,WorkManager 提供了很大的灵活性。您可以将其安排为在某段时间内定期运行,也可以将其安排为仅运行一次。
不论您选择以何种方式调度工作,请始终使用 WorkRequest。Worker 定义工作单元,WorkRequest(及其子类)则定义工作运行方式和时间。在最简单的情况下,您可以使用 OneTimeWorkRequest
提交work执行:
val workRequest:WorkRequest=OneTimeWorkRequestBuilder<MyWorks>().build()
WorkManager.getInstance(application).enqueue(workRequest)
这种是一次性调度。
也可以通过from来创建request:
val workRequest= OneTimeWorkRequest.from(MyWorks::class.java)
这种构建也只能构建简单的
复杂构建:
复杂的构建需要通过OneTimeWorkRequestBuilder来构建
val build=OneTimeWorkRequestBuilder<MyWorks>() 通过build来设置加载机制和延迟等
调度加急
WorkManager 2.7.0 引入了加急工作的概念。这使 WorkManager 能够执行重要工作,同时使系统能够更好地控制对资源的访问权限。
加急工作具有以下特征:
- 重要性:加急工作适用于对用户很重要或由用户启动的任务。
- 速度:加急工作最适合那些立即启动并在几分钟内完成的简短任务。
- 配额:限制前台执行时间的系统级配额决定了加急作业是否可以启动。
- 电源管理:电源管理限制(如省电模式和低电耗模式)不太可能影响加急工作。
- 延迟时间:系统立即执行加急工作,前提是系统的当前工作负载允许执行此操作。这意味着这些工作对延迟时间较为敏感,不能安排到以后执行。
执行加急
从 WorkManager 2.7 开始,您的应用可以调用 setExpedited()
来声明 WorkRequest
应该使用加急作业,以尽可能快的速度运行。以下代码段展示了关于如何使用 setExpedited()
的示例
val request = OneTimeWorkRequestBuilder() .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) .build()
向后兼容性和前台服务
为了保持加急作业的向后兼容性,WorkManager 可能会在 Android 12 之前版本的平台上运行前台服务。前台服务可以向用户显示通知。
在 Android 12 之前,工作器中的 getForegroundInfoAsync()
和 getForegroundInfo()
方法可让 WorkManager 在您调用 setExpedited()
时显示通知。
如果您想要请求任务作为加急作业运行,则所有的 ListenableWorker 都必须实现 getForegroundInfo
方法
override fun getForegroundInfoAsync(): ListenableFuture<ForegroundInfo> {
return super.getForegroundInfoAsync()
}
CoroutineWorker:
如果您使用 CoroutineWorker
,则必须实现 getForegroundInfo()
。然后,在 doWork()
内将其传递给 setForeground()
。这样做会在 Android 12 之前的版本中创建通知
override suspend fun getForegroundInfo(): ForegroundInfo {
val id = Random.nextInt(0, Int.MAX_VALUE)
return ForegroundInfo(id, getNotion())
}
private fun getNotion(): Notification {
val notification = Notification()
return notification;
}
配额政策:
OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST:
这会导致作业作为普通工作请求运行。上述代码段演示了此操作。
OutOfQuotaPolicy.DROP_WORK_REQUEST
这会在配额不足时导致请求取消。
定期调度
您的应用有时可能需要定期运行某些工作,使用 PeriodicWorkRequest 创建定期执行的 WorkRequest
val request=PeriodicWorkRequestBuilder<MyWorks>(5,TimeUnit.MILLISECONDS)
解释:
时间间隔定义为两次重复执行之间的最短时间。工作器的确切执行时间取决于您在 WorkRequest 对象中设置的约束以及系统执行的优化。
val reques1=PeriodicWorkRequestBuilder<MyWorks>(5,TimeUnit.HOURS,15,TimeUnit.MINUTES)
重复间隔必须大于或等于 PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,而灵活间隔必须大于或等于 PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS
/**
* The minimum interval duration for {@link PeriodicWorkRequest} (in milliseconds).
*/
@SuppressLint("MinMaxConstant")
public static final long MIN_PERIODIC_INTERVAL_MILLIS = 15 * 60 * 1000L; // 15 minutes.
/**
* The minimum flex duration for {@link PeriodicWorkRequest} (in milliseconds).
*/
@SuppressLint("MinMaxConstant")
public static final long MIN_PERIODIC_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes.
repeatInterval :重复的时间值
flexInterval:第二个时间值,
约束
约束可确保将工作延迟到满足最佳条件时运行。以下约束适用于 WorkManager
NetworkType | 约束运行工作所需的网络类型。例如 Wi-Fi (UNMETERED )。 |
BatteryNotLow | 如果设置为 true,那么当设备处于“电量不足模式”时,工作不会运行。 |
RequiresCharging | 如果设置为 true,那么工作只能在设备充电时运行。 |
DeviceIdle | 如果设置为 true,则要求用户的设备必须处于空闲状态,才能运行工作。在运行批量操作时,此约束会非常有用;若是不用此约束,批量操作可能会降低用户设备上正在积极运行的其他应用的性能。 |
StorageNotLow | 如果设置为 true,那么当用户设备上的存储空间不足时,工作不会运行。 |
如需创建一组约束并将其与某项工作相关联,请使用一个 Contraints.Builder()
创建 Constraints
实例,并将该实例分配给 WorkRequest.Builder()
。
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresCharging(true)
.build()
val myWorkRequest: WorkRequest =
OneTimeWorkRequestBuilder<MyWorks>()
.setConstraints(constraints)
.build()
如果指定了多个约束,工作将仅在满足所有约束时才会运行。
如果在工作运行时不再满足某个约束,WorkManager 将停止工作器。系统将在满足所有约束后重试工作。
延迟:
如果您不希望工作立即运行,可以将工作指定为在经过一段最短初始延迟时间后再启动
al myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
.setInitialDelay(10, TimeUnit.MINUTES)
.build()
这个延迟和handler的延迟机制是一样使用。PeriodicWorkRequest
设置初始延迟时间,在这种情况下,定期工作只有首次运行时会延迟。
重试和退避
如果您需要让 WorkManager 重试工作,可以从工作器返回 Result.retry()
。然后,系统将根据退避延迟时间和退避政策重新调度工作。
-
退避延迟时间指定了首次尝试后重试工作前的最短等待时间。此值不能超过 10 秒(或 MIN_BACKOFF_MILLIS)。
-
退避政策定义了在后续重试过程中,退避延迟时间随时间以怎样的方式增长。WorkManager 支持 2 个退避政策,即
LINEAR
和EXPONENTIAL
。
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>() .setBackoffCriteria( BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS) .build()
最短退避延迟时间设置为允许的最小值,即 10 秒。由于政策为 LINEAR
,每次尝试重试时,重试间隔都会增加约 10 秒。例如,第一次运行以 Result.retry()
结束并在 10 秒后重试;然后,如果工作在后续尝试后继续返回 Result.retry()
,那么接下来会在 20 秒、30 秒、40 秒后重试,以此类推。如果退避政策设置为 EXPONENTIAL
,那么重试时长序列将接近 20、40、80 秒,以此类推。
标记
在request的对象中,都支持setTag,方便我们在获取对象时,可以通标记值来获取。这个类似线程池获取某个线程一样,只要我们知道线程的名字,就能准确的找到
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>() .addTag("cleanup") .build()
数据绑定:
在处理异步操作时,必然和数据打交道,如何传递数据呢?通过Data来传递
通过request的setInputData来完成,我们在override fun doWork(): Result{}中,获取到
override fun doWork(): Result { //数据集合 var data= inputData; return retry }
同样,也可以将结果通过Resukt返回出去。