此 Codelab 是“Android Kotlin 基础知识”课程的一部分。如果您按顺序学习这些 Codelab,您将会充分发掘此课程的价值。“Android Kotlin 基础知识”Codelab 着陆页列出了所有课程 Codelab。
简介
大多数实际应用都需要执行长时间运行的后台任务。例如,应用可能会将文件上传到服务器、从服务器同步数据并将其保存到 Room 数据库、将日志发送到服务器,或者对数据执行开销较大的操作。此类操作应在后台(而非界面线程 [主线程])中执行。后台任务会使用设备的有限资源,例如 RAM 和电池电量。如果处理不当,可能会导致用户体验不佳。
在此 Codelab 中,您将学习如何使用 WorkManager 以经优化、高效的方式调度后台任务。如需详细了解 Android 中可用于后台处理的其他解决方案,请参阅后台处理指南。
您应当已掌握的内容
- 如何使用 ViewModel、LiveData和RoomAndroid 架构组件。
- 如何对 LiveData类执行转换。
- 如何构建和启动协程。
- 如何在数据绑定中使用绑定适配器。
- 如何使用存储库模式加载缓存的数据。
学习内容
- 如何创建 Worker,表示一个工作单元。
- 如何创建 WorkRequest以请求执行工作。
- 如何向 WorkRequest添加约束条件,以定义 worker 的运行方式和时间。
- 如何使用 WorkManager安排后台任务。
您将执行的操作
- 创建一个工作器,用于执行后台任务以从网络预提取 DevBytes 视频播放列表。
- 安排工作器定期运行。
- 为 WorkRequest添加约束条件。
- 安排定期执行的 WorkRequest,每天执行一次。
在此 Codelab 中,您将使用在上一个 Codelab 中开发的 DevBytes 应用。(如果您没有此应用,可以下载本节课的起始代码。)
DevBytes 应用会显示一个 DevByte 视频列表,这些视频是由 Google Android 开发者关系团队制作的简短教程。这些视频介绍了 Android 开发的开发者功能和最佳实践。
您每天预提取一次视频,从而提升应用中的用户体验。这样可确保用户在打开应用后立即获得新内容。

在此任务中,您将下载并检查起始代码。
第 1 步:下载并运行起始应用
您可以继续使用在上一个 Codelab 中构建的 DevBytes 应用(如果您有)。或者,您也可以下载初始应用。
在此任务中,您将下载并运行起始应用,并检查起始代码。
- 如果您还没有 DevBytes 应用,请从 GitHub 的 DevBytesRepository 项目下载此 Codelab 的 DevBytes 起始代码。
- 解压缩代码,然后在 Android Studio 中打开项目。
- 将测试设备或模拟器连接到互联网(如果尚未连接)。构建并运行应用。该应用会从网络中提取 DevByte 视频列表并显示这些视频。
- 在应用中,点按任意视频即可在 YouTube 应用中打开该视频。
第 2 步:探索代码
起始应用附带了上一个 Codelab 中介绍的许多代码。本 Codelab 的起始代码包含网络、界面、离线缓存和代码库模块。您可以专注于使用 WorkManager 安排后台任务。
- 在 Android Studio 中,展开所有软件包。
- 探索 database软件包。该软件包包含数据库实体和使用Room实现的本地数据库。
- 探索 repository软件包。该软件包包含VideosRepository类,该类可从应用的其余部分中提取数据层。
- 在之前 Codelab 的帮助下,自行探索其余的起始代码。
WorkManager 是 Android 架构组件之一,也是 Android Jetpack 的一部分。WorkManager 适用于可延迟且需要保证执行的后台工作:
- 可延迟表示工作不需要立即运行。例如,将分析数据发送到服务器或在后台同步数据库是可以延迟的工作。
- 有保证的执行意味着即使应用退出或设备重启,任务也会运行。

在 WorkManager 运行后台工作时,它会处理兼容性问题,并遵循电池和系统健康度最佳实践。WorkManager 可向后兼容至 API 级别 14。WorkManager 会根据设备 API 级别选择安排后台任务的适当方式。它可能会使用 JobScheduler(在 API 23 及更高版本上)或 AlarmManager 和 BroadcastReceiver 的组合。
您还可以使用 WorkManager 设置后台任务的运行条件。例如,您可能希望仅当电池状态、网络状态或充电状态满足特定条件时才运行任务。您将在本 Codelab 的后面部分学习如何设置限制条件。
在此 Codelab 中,您将安排一项任务,以每天从网络中预提取一次 DevBytes 视频播放列表。如需安排此任务,请使用 WorkManager 库。
- 打开 build.gradle (Module:app)文件,并将WorkManager依赖项添加到项目中。
 如果您使用该库的最新版本,解决方案应用应能按预期进行编译。如果不是,请尝试解决问题,或恢复到下方显示的库版本。
// WorkManager dependency
def work_version = "1.0.1"
implementation "android.arch.work:work-runtime-ktx:$work_version"- 同步项目,并确保没有编译错误。
在向项目添加代码之前,请先熟悉 WorkManager 库中的以下类:
- Worker
 您可以在此类中定义要在后台运行的实际工作(任务)。您需要扩展此类并替换- doWork()方法。- doWork()方法用于放置要在后台执行的代码,例如与服务器同步数据或处理图片。您将在此任务中实现- Worker。
- WorkRequest
 此类表示在后台运行工作器的请求。使用- WorkRequest配置运行工作器任务的方式和时间,并借助- Constraints(例如设备已插电或已连接到 Wi-Fi)来完成配置。您将在后面的任务中实现- WorkRequest。
- WorkManager
 此类会调度并运行您的- WorkRequest。- WorkManager以一种在系统资源上分散负载的方式调度工作请求,同时遵循您指定的约束条件。您将在后面的任务中实现- WorkManager。
第 1 步:创建工作者
在此任务中,您将添加一个 Worker 以在后台预提取 DevBytes 视频播放列表。
- 在 devbyteviewer软件包中,新建一个名为work的软件包。
- 在 work软件包中,创建一个名为RefreshDataWorker的新 Kotlin 类。
- 从 CoroutineWorker类扩展RefreshDataWorker类。传入context和WorkerParameters作为构造函数参数。
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
}- 如需解决抽象类错误,请替换 RefreshDataWorker类中的doWork()方法。
override suspend fun doWork(): Result {
  return Result.success()
}挂起函数是一种可以暂停并在稍后恢复的函数。挂起函数可以执行长时间运行的操作,并等待其完成,而不会阻塞主线程。
第 2 步:实现 doWork()
Worker 类中的 doWork() 方法是在后台线程上调用的。该方法会同步执行工作,并应返回一个 ListenableWorker.Result 对象。Android 系统最多允许 Worker 在 10 分钟内完成执行并返回 ListenableWorker.Result 对象。此时间过期后,系统会强制停止 Worker。
如需创建 ListenableWorker.Result 对象,请调用以下静态方法之一来指示后台工作的完成状态:
- Result.success()- 工作已成功完成。
- Result.failure()- 工作已完成,但出现永久性失败。
- Result.retry()- 工作遇到暂时性故障,应重试。
在此任务中,您将实现 doWork() 方法,以从网络中提取 DevBytes 视频播放列表。您可以重复使用 VideosRepository 类中的现有方法从网络中检索数据。
- 在 RefreshDataWorker类中,在doWork()内,创建并实例化一个VideosDatabase对象和一个VideosRepository对象。
override suspend fun doWork(): Result {
   val database = getDatabase(applicationContext)
   val repository = VideosRepository(database)
   return Result.success()
}- 在 RefreshDataWorker类中,在doWork()内的return语句上方,在try块内调用refreshVideos()方法。添加了一个日志来跟踪工作器的运行时间。
try {
   repository.refreshVideos( )
   Timber.d("Work request for sync is run")
   } catch (e: HttpException) {
   return Result.retry()
}如需解决“Unresolved reference”错误,请导入 retrofit2.HttpException。
- 以下是完整的 RefreshDataWorker类,供您参考:
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
   override suspend fun doWork(): Result {
       val database = getDatabase(applicationContext)
       val repository = VideosRepository(database)
       try {
           repository.refreshVideos()
       } catch (e: HttpException) {
           return Result.retry()
       }
       return Result.success()
   }
}Worker 定义工作单元,WorkRequest 则定义工作的运行方式和时间。WorkRequest 类有两个具体实现:
- OneTimeWorkRequest类适用于一次性任务。(一次性任务仅发生一次。)
- PeriodicWorkRequest类适用于按时间间隔重复的定期工作。
任务可以是一次性的,也可以是周期性的,因此请相应地选择任务类别。如需详细了解如何调度周期性工作,请参阅周期性工作文档。
在此任务中,您将定义并安排一个 WorkRequest 来运行您在上一个任务中创建的 worker。
第 1 步:设置周期性工作
在 Android 应用中,Application 类是包含所有其他组件(例如 activity 和服务)的基类。在创建应用或软件包的进程时,系统会在任何其他类之前实例化 Application 类(或 Application 的任何子类)。
在此示例应用中,DevByteApplication 类是 Application 类的子类。DevByteApplication 类是安排 WorkManager 的好地方。
- 在 DevByteApplication类中,创建一个名为setupRecurringWork()的方法来设置周期性后台工作。
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}- 在 setupRecurringWork()方法内,使用PeriodicWorkRequestBuilder()方法创建并初始化一个每天运行一次的周期性工作请求。传入您在上一个任务中创建的RefreshDataWorker类。传入重复间隔时间1,时间单位为TimeUnit.DAYS。
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .build()如需解决此错误,请导入 java.util.concurrent.TimeUnit。
第 2 步:使用 WorkManager 调度 WorkRequest
定义 WorkRequest 后,您可以使用 enqueueUniquePeriodicWork() 方法通过 WorkManager 来调度它。此方法可让您向队列添加具有唯一名称的 PeriodicWorkRequest,其中一次只能有一个具有特定名称的 PeriodicWorkRequest 处于活动状态。
例如,您可能只希望有一项同步操作处于活跃状态。如果有一个同步操作处于待处理状态,您可以选择让其运行,也可以使用 ExistingPeriodicWorkPolicy 将其替换为新工作。
如需详细了解如何安排 WorkRequest,请参阅 WorkManager 文档。
- 在 RefreshDataWorker类中,于类开头处添加一个伴生对象。定义一个工作名称,以唯一标识此 worker。
companion object {
   const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}- 在 DevByteApplication类中,在setupRecurringWork()方法的末尾,使用enqueueUniquePeriodicWork()方法安排工作。为 ExistingPeriodicWorkPolicy 传入KEEP枚举。传入repeatingRequest作为PeriodicWorkRequest参数。
WorkManager.getInstance().enqueueUniquePeriodicWork(
       RefreshDataWorker.WORK_NAME,
       ExistingPeriodicWorkPolicy.KEEP,
       repeatingRequest)如果存在同名的待处理(未完成)工作,ExistingPeriodicWorkPolicy.KEEP 参数会使 WorkManager 保留之前的周期性工作并舍弃新的工作请求。
- 在 DevByteApplication类的开头,创建一个CoroutineScope对象。传入Dispatchers.Default作为构造函数参数。
private val applicationScope = CoroutineScope(Dispatchers.Default)- 在 DevByteApplication类中,添加一个名为delayedInit()的新方法以启动协程。
private fun delayedInit() {
   applicationScope.launch {
   }
}- 在 delayedInit()方法内,调用setupRecurringWork()。
- 将 Timber 初始化从 onCreate()方法移至delayedInit()方法。
private fun delayedInit() {
   applicationScope.launch {
       Timber.plant(Timber.DebugTree())
       setupRecurringWork()
   }
}- 在 DevByteApplication类中,在onCreate()方法的末尾,添加对delayedInit()方法的调用。
override fun onCreate() {
   super.onCreate()
   delayedInit()
}- 打开 Android Studio 窗口底部的 Logcat 窗格。过滤条件:RefreshDataWorker。
- 运行应用。WorkManager会立即安排您的周期性工作。
 在 Logcat 窗格中,注意显示工作请求已安排并成功运行的日志语句。
D/RefreshDataWorker: Work request for sync is run I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
WM-WorkerWrapper 日志是从 WorkManager 库中显示的,因此您无法更改此日志消息。
第 3 步:(可选)安排 WorkRequest 以最小间隔运行
在此步骤中,您将时间间隔从 1 天缩短到 15 分钟。这样做是为了查看定期工作请求的实际日志。
- 在 DevByteApplication类中,在setupRecurringWork()方法内,注释掉当前的repeatingRequest定义。添加一个周期性重复间隔为15分钟的新工作请求。
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
//        .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
       .build()- 在 Android Studio 中打开 Logcat 窗格,并按 RefreshDataWorker进行过滤。如需清除之前的日志,请点击 Clear logcat 图标 。 。
- 运行应用,WorkManager会立即安排重复性工作。在 Logcat 窗格中,注意日志 - 工作请求每 15 分钟运行一次。等待 15 分钟,查看另一组工作请求日志。您可以让应用保持运行状态,也可以将其关闭;工作管理器应仍会运行。
 请注意,间隔有时不到 15 分钟,有时超过 15 分钟。(确切时间取决于操作系统电池优化。)
12:44:40 D/RefreshDataWorker: Work request for sync is run 12:44:40 I/WM-WorkerWrapper: Worker result SUCCESS for Work 12:59:24 D/RefreshDataWorker: Work request for sync is run 12:59:24 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:15:03 D/RefreshDataWorker: Work request for sync is run 13:15:03 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:29:22 D/RefreshDataWorker: Work request for sync is run 13:29:22 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:44:26 D/RefreshDataWorker: Work request for sync is run 13:44:26 I/WM-WorkerWrapper: Worker result SUCCESS for Work
 恭喜!您创建了一个 worker,并使用 WorkManager 调度了工作请求。但有一个问题:您未指定任何限制。WorkManager 会每天安排一次工作,即使设备电池电量不足、处于休眠状态或没有网络连接也是如此。这会影响设备电池和性能,并可能导致糟糕的用户体验。
在下一个任务中,您将通过添加限制来解决此问题。
在上一个任务中,您使用 WorkManager 安排了工作请求。在此任务中,您将添加用于指定何时执行工作的条件。
定义 WorkRequest 时,您可以指定 Worker 的运行时间限制。例如,您可能希望指定工作应仅在设备空闲时运行,或者仅在设备已插电并连接到 Wi-Fi 时运行。您还可以指定用于重试工作的退避政策。支持的限制条件是 Constraints.Builder 中的设置方法。如需了解详情,请参阅定义工作请求。
第 1 1 步:添加 Constraints 对象并设置一个约束条件
在此步骤中,您将创建一个 Constraints 对象,并为该对象设置一个限制条件(即网络类型限制条件)。(如果只有一个限制条件,则更容易注意到日志。在后续步骤中,您将添加其他限制条件。)
- 在 DevByteApplication类中,在setupRecurringWork()的开头,定义一个类型为Constraints的val。使用Constraints.Builder()方法。
val constraints = Constraints.Builder()如需解决此错误,请导入 androidx.work.Constraints。
- 使用 setRequiredNetworkType()方法向constraints对象添加网络类型限制。使用UNMETERED枚举,以便工作请求仅在设备连接到不按流量计费的网络时运行。
.setRequiredNetworkType(NetworkType.UNMETERED)- 使用 build()方法从构建器生成约束条件。
val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .build()现在,您需要将新创建的 Constraints 对象设置为工作请求。
- 在 DevByteApplication类中,在setupRecurringWork()方法内,将Constraints对象设置为周期性工作请求repeatingRequest。如需设置限制条件,请在build()方法调用上方添加setConstraints()方法。
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
               .setConstraints(constraints)
               .build()第 2 步:运行应用并注意日志
在此步骤中,您将运行应用,并注意到受限工作请求正在后台以一定的时间间隔运行。
- 从设备或模拟器中卸载应用,以取消之前排定的所有任务。
- 在 Android Studio 中打开 Logcat 窗格。在 Logcat 窗格中,点击左侧的清除 Logcat 图标 ,清除之前的日志。过滤条件: ,清除之前的日志。过滤条件:work。
- 关闭设备或模拟器中的 Wi-Fi,以便了解约束条件的工作方式。当前代码仅设置了一个限制条件,即请求应仅在非按流量计费的网络上运行。由于 Wi-Fi 已关闭,设备未连接到任何网络(按流量计费或不按流量计费)。因此,此限制条件将无法满足。
- 运行应用,然后注意 Logcat 窗格。WorkManager会立即安排后台任务。由于未满足网络限制,因此未运行该任务。
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
- 在设备或模拟器中开启 Wi-Fi,然后观察 Logcat 窗格。现在,只要满足网络限制条件,调度的后台任务就会大约每 15 分钟运行一次。
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled 11:31:47 D/RefreshDataWorker: Work request for sync is run 11:31:47 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 11:46:45 D/RefreshDataWorker: Work request for sync is run 11:46:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:03:05 D/RefreshDataWorker: Work request for sync is run 12:03:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:16:45 D/RefreshDataWorker: Work request for sync is run 12:16:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:31:45 D/RefreshDataWorker: Work request for sync is run 12:31:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:47:05 D/RefreshDataWorker: Work request for sync is run 12:47:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 13:01:45 D/RefreshDataWorker: Work request for sync is run 13:01:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
第 3 步:添加更多限制条件
在此步骤中,您将向 PeriodicWorkRequest 添加以下限制条件:
- 电池电量不低。
- 设备正在充电。
- 设备处于空闲状态;仅适用于 API 级别 23 (Android M) 及更高版本。
在 DevByteApplication 类中实现以下各项。
- 在 DevByteApplication类中的setupRecurringWork()方法内,指明工作请求应仅在电池电量不低时运行。在build()方法调用之前添加限制,并使用setRequiresBatteryNotLow()方法。
.setRequiresBatteryNotLow(true)- 更新工作请求,使其仅在设备充电时运行。在 build()方法调用之前添加限制,并使用setRequiresCharging()方法。
.setRequiresCharging(true)- 更新工作请求,使其仅在设备处于空闲状态时运行。在 build()方法调用之前添加限制,并使用setRequiresDeviceIdle()方法。此约束条件仅在用户未主动使用设备时运行工作请求。此功能仅适用于 Android 6.0 (Marshmallow) 及更高版本,因此请添加 SDK 版本M及更高版本的条件。
.apply {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
       setRequiresDeviceIdle(true)
   }
}以下是 constraints 对象的完整定义。
val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .setRequiresBatteryNotLow(true)
       .setRequiresCharging(true)
       .apply {
           if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
               setRequiresDeviceIdle(true)
           }
       }
       .build()- 在 setupRecurringWork()方法内,将请求间隔改回每天一次。
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .setConstraints(constraints)
       .build()以下是 setupRecurringWork() 方法的完整实现,其中包含一个日志,以便您跟踪何时安排了周期性工作请求。
private fun setupRecurringWork() {
       val constraints = Constraints.Builder()
               .setRequiredNetworkType(NetworkType.UNMETERED)
               .setRequiresBatteryNotLow(true)
               .setRequiresCharging(true)
               .apply {
                   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                       setRequiresDeviceIdle(true)
                   }
               }
               .build()
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
               .setConstraints(constraints)
               .build()
       
       Timber.d("Periodic Work request for sync is scheduled")
       WorkManager.getInstance().enqueueUniquePeriodicWork(
               RefreshDataWorker.WORK_NAME,
               ExistingPeriodicWorkPolicy.KEEP,
               repeatingRequest)
   }- 如需移除之前安排的工作请求,请从设备或模拟器中卸载 DevBytes 应用。
- 运行应用,WorkManager会立即调度工作请求。工作请求每天运行一次,前提是满足所有约束条件。
- 只要应用已安装,即使未运行,此工作请求也会在后台运行。因此,您应从手机中卸载该应用。
太棒了!您为 DevBytes 应用中视频的每日预提取实现了并安排了省电的工作请求。WorkManager 将安排并运行该工作,从而优化系统资源。您的用户及其电池会非常满意。
Android Studio 项目:DevBytesWorkManager。
- 使用 WorkManagerAPI 可以轻松调度必须可靠运行的可延期异步任务。
- 大多数实际应用都需要执行长时间运行的后台任务。如需以经优化、高效的方式调度后台任务,请使用 WorkManager。
- WorkManager库中的主要类为- Worker、- WorkRequest和- WorkManager。
- Worker类表示工作单元。如需实现后台任务,请扩展- Worker类并替换- doWork()方法。
- WorkRequest类表示执行工作单元的请求。- WorkRequest是用于指定在- WorkManager中安排的工作的参数的基类。
- WorkRequest类有两个具体实现:- OneTimeWorkRequest用于一次性任务,- PeriodicWorkRequest用于周期性工作请求。
- 在定义 WorkRequest时,您可以指定Constraints来指明Worker应何时运行。限制条件包括设备是否已接通电源、设备是否处于空闲状态,以及是否已连接到 Wi-Fi 等。
- 如需向 WorkRequest添加限制,请使用Constraints.Builder文档中列出的设置方法。例如,如需指明当设备电池电量不足时,不应运行WorkRequest,请使用setRequiresBatteryNotLow()设置方法。
- 定义 WorkRequest后,将任务提交给 Android 系统。为此,请使用WorkManagerenqueue方法安排任务。
- Worker的确切执行时间取决于- WorkRequest中使用的约束以及系统优化。- WorkManager经过专门设计,能够在满足这些约束的情况下提供可能的最佳行为。
Udacity 课程:
Android 开发者文档:
其他:
此部分列出了在由讲师主导的课程中,学生学习此 Codelab 后可能需要完成的家庭作业。讲师自行决定是否执行以下操作:
- 根据需要布置作业。
- 告知学生如何提交家庭作业。
- 给家庭作业评分。
讲师可以酌情采纳这些建议,并且可以自由布置自己认为合适的任何其他家庭作业。
如果您是在自学此 Codelab,可随时通过这些家庭作业来检测您的知识掌握情况。
问题 1
WorkRequest 类的具体实现是什么?
▢ OneTimeWorkPeriodicRequest
▢ OneTimeWorkRequest 和 PeriodicWorkRequest
▢ OneTimeWorkRequest 和 RecurringWorkRequest
▢ OneTimeOffWorkRequest 和 RecurringWorkRequest
问题 2
WorkManager 使用以下哪个类在运行 API 23 及更高级别的设备上调度后台任务?
▢ 仅限 JobScheduler
▢ BroadcastReceiver 和 AlarmManager
▢ AlarmManager 和 JobScheduler
▢ Scheduler 和 BroadcastReceiver
问题 3
使用哪个 API 向 WorkRequest 添加约束条件?
▢ setConstraints()
▢ addConstraints()
▢ setConstraint()
▢ addConstraintsToWorkRequest()
开始学习下一课:
如需本课程中其他 Codelab 的链接,请参阅“Android Kotlin 基础知识”Codelab 着陆页。