一、简介

Android有多个选项用于处理可推迟的后台作业。WorkManager是一种具有向后兼容性且简略灵敏的库,用于处理可推迟的后台作业。WorkManager是Android平台上引荐用于处理可推迟作业的使命调度程序,可以确保作业得到履行。

1.1、什么是WorkManager

WorkManager归于Android Jetpack的一部分,是一种架构组件,用于处理既需求时机性履行,又需求有确保的履行的后台作业。时机性履行意味着WorkManager会尽快履行您的后台作业。有确保的履行意味着WorkManager会负责通过逻辑妨碍在各种情况下发动您的作业,即便用户脱离您的运用也不妨。

WorkManager是一个极其灵敏的库,具有许多其他优势。这其间包括:

  • 支撑异步一次性使命和定时使命
  • 支撑网络条件、存储空间和充电状况等束缚条件
  • 链接复杂的作业恳求,包括并行运转作业
  • 将来自一个作业恳求的输出用作下一个作业恳求的输入
  • 处理到API级别的兼容性,可向后兼容至API级别14
  • 不管是否运用Google Play服务都可以运转
  • 遵从体系健康最佳做法
  • 供给LiveData支撑,可在界面轻松显现作业恳求状况

1.2、何时运用WorkManager

有些使命,即便用户脱离特定屏幕或您的运用,也需求完结。关于这些使命,WorkManager库是不错的挑选。

以下是一些适合运用Work的使命的典型示例:

  • 上传日志
  • 对图片运用滤镜并保存图片
  • 定时将本地数据与网络同步

WorkManager供给有确保的履行,然而并非一切使命都需求这种确保。因而,它并非运转一切非主线程使命的万全之选。

1.3、后台处理

1.3.1、后台使命的类别

后台使命分为以下几个首要类别:

  • 即时使命
  • 延期使命
  • 准确使命

如需对使命进行分类,请答复以下问题。

使命是否需求在用户与运用进行互动时完结?

假如是,则应将使命归类为即时使命。假如不是,请持续答复第二个问题。

使命是否需求在准确的时刻点运转?

假如您确定需求在准确的时刻点运转使命,则应将使命归类为准确使命。

大多数使命不需求在准确的时刻点运转。一般,使命允许运转的时刻点存在纤细差异,具体取决于网络可用性和剩余电量等条件。无需在准确时刻点运转的使命应归类为延期使命。

1.3.2、引荐的解决方案

下面几部分将介绍针对各个后台使命类型的引荐解决方案。

1.3.2.1、即时使命

关于应在用户脱离特定效果域或完结某项互动时完毕的使命,咱们主张运用Kotlin 协程。许多Android KTX库都包括适用于常见运用组件(如ViewModel)和常见运用生命周期的现成可用的协程效果域。

假如您是 Java 编程语言用户,请参阅Android 上的线程处理,了解引荐的选项。

关于应立即履行并需求持续处理的使命,即便用户将运用放在后台运转或重启设备,咱们也主张运用WorkManager并运用其对长时刻运转的使命的支撑。

在特定情况下(例如运用媒体播映或主动导航功能时),您或许期望直接运用前台服务。

1.3.2.2、延期使命

凡是不直接与用户互动相关切日后随时运转的使命,都可以延期履行。主张为延期使命运用WorkManager解决方案。

假如您期望某些可延期异步使命即便在退出或设备重启后仍能正常运转,运用WorkManager可以轻松地调度这些使命。

1.3.2.3、准确使命

需求在准确时刻点履行的使命可以运用AlarmManager

1.4、构建内容

现在,智能手机的拍照功能根本都很强大。

您将运用Blur-O-Matic,该运用对相片进行含糊处理,并将处理后的相片保存到文件中。

使用WorkManager在后台处理工作 - Kotlin(上)

1.5、学习内容

✅ 将WorkManager增加到您的项目中 ✅ 调度简略的使命 ✅ 输入和输出参数 ✅ 链接Work ✅ 仅有Work ✅ 在界面中显现Work状况 ✅ 取消Work ✅ Work束缚

二、准备作业

假如愿意,您可以从 GitHub 克隆 WorkManager Codelab:

$ git clone -b start_kotlin https://github.com/googlecodelabs/android-workmanager

运转运用, 您应该会看到下方的屏幕。

使用WorkManager在后台处理工作 - Kotlin(上)

屏幕上应该会显现一些单选按钮,您可以通过这些按钮要对图片进行什么程度的含糊处理。按Go按钮即可对图片进行含糊处理并保存。

截止现在,此运用不会运用任何含糊处理。

开始代码包括以下内容:

  • WorkerUtils:这个类包括对图片实际进行含糊处理所需的代码,并包括之后您会用于显现Notifications、将位图保存到图片以及减慢运用运转速度的一些快捷办法。
  • BlurActivity:*此activity用于显现图片以及增加用于挑选含糊程度的单选按钮。
  • BlurViewModel:*此视图模型用于存储显现BlurActivity所需的一切数据,也将是您运用WorkManager发动后台作业的类。
  • Constants:一个静态类,其间包括一些常量。
  • res/activity_blur.xmlBlurActivity的布局文件。

三、将WorkManager增加到您的运用

WorkManager需求运用一下Gradle依靠项,这些依靠项已包括在build文件中:

app/build.gradle

dependencies {
    // WorkManager dependency
    implementation "androidx.work:work-runtime-ktx:$versions.work"
}

build.gradle

version.work = "2.7.1"

四、创立您的第一条WorkRequest

在此步骤中,您将承受res/drawable文件夹中一张名为android_cupcake.png的图片,并在后台对这张图片运转一些函数。这些函数会对图片进行含糊处理,然后将图片保存到临时文件中。

4.1、WorkManager基础知识

您需求了解一下几个WorkManager类:

  • Worker:此方位用于放置您期望在后台履行的实际作业的代码。您需求扩展此替换doWork()办法。
  • WorkQuest:此类表示恳求履行某些Work。您将在创立WorkRequest的过程中传入Worker。在创立WorkRequst时,您还可以指定Constraints等内容,例如运转Worker的时刻。
  • WorkManager:这个类实质上可以调度WorkRequest并使其运转。它以一种在体系资源上涣散负载的办法调度WorkRequest,一起遵从您指定的束缚条件。

在这种情况下, 您将界说新的BlurWorker,其间包括用于对图片记性含糊处理的代码。点击Go按钮时,体系会创立一个WorkRequest,然后通过WorkManager将其参加行列。

4.1.1、第1步 – 创立BlurWorker

workers软件包中,新建一个名为BlurWorker的Kotlin类

4.2.1、第2步 – 增加结构函数

BlurWorker类增加的Worker的依靠项:

class BlurWorker(ctx: Context, params: WorkerParameters): Worker(ctx, params) {
}

4.2.3、第3步 – 替换和实现doWork()

worker会对所显现的纸杯蛋糕图片进行含糊处理。

为了更好地了解何时履行作业,您将运用WorkerUtilmakeStatusNotification()。运用此办法,您可以轻松地在屏幕顶部显现告诉横幅。

替换doWork()办法,然后履行以下操作。您可以参考本部分末尾完结后的代码:

  1. 通过调用applicationContext特点获取Context。将其分配给名为appContext的新val。接下来要履行的各种位图处理需求用到的此参数。
  2. 运用函数makeStatusNotification显现状况告诉,以像用户发送有关对图片进行含糊处理的告诉。
  3. 运用纸杯蛋糕图片创立一个Bitmap:
val picture = BitmapFactory.decodeResource(appContext.resource, R.drawable.android_cupcake)
  1. 通过从WorkerUtils调用blurBitmap办法,获取此位图含糊处理后的版本。
  2. WorkerUtils调用writeBitmapToFile办法,将该位图写入临时文件。请务必将回来的URI保存到局部变量。
  3. WorkerUtils调用makeStatusNotification办法,以创立显现URI的告诉。
  4. 回来Result.success()
  5. try/catch句子中封装第3-6步的代码。捕获通用的Throwable
  6. 在catch句子中,运用日志句子Log.e(TAG, "Error applying blur")输出错误音讯。
  7. 然后再catch句子中回来Result.failure

此步骤的完好代码如下所示:

BlurWorker.kt

package com.example.background.workers
import android.content.Context
import android.graphics.BitmapFactory
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.example.background.R
private const val TAG = "BlurWorker"
class BlurWorker(ctx: Context, params: WorkerParameters): Worker(ctx, params) {
    override fun doWork(): Result {
        val appContext = applicationContext
        makeStatusNotification("Blurring image", appContext)
        return try {
            val picture = BitmapFactory.decodeResource(
                appContext.resource,
                R.drawable.android_cupcake
            )
            val output = blurBitmap(picture, appContext)
            // Write bitmap to a temp file
            val outputUri = writeBitmapToFile(appContext, output)
            makeStatusNotification("Output is @outputUri", appContext)
            Result.success()
        } catch (throwable: Throwable) {
            Log.e(TAG, "Error applying blur")
            Result.failure()
        }
    }
}

4.2.4、第4步 – 在ViewModel中获取WorkManager

ViewModel中为WorkManager实例创立类变量:

BlurViewModel.kt

privagte val workManager = WorkManager.getInstance(application)

4.2.5、第5步 – 在WorkManager中将WorkRequest参加行列

现在是时分设置WorkRequest并指示WorkManager运转它了。WorkRequest有两种类型:

  • OneTimeWorkRequest: 仅履行一次的WorkRequest
  • PeriodicWorkRequest:按周期重复履行的WorkRequest

咱们只期望在点击Go按钮后对图片进行含糊处理。当用户点击Go按钮时,体系会调用applyBlur办法,因而请通过BlurWorker创立OneTimeWorkRequest。然后,运用WorkManager实例将您的WorkRequest参加行列。

将以下代码行增加到BlurViewModel``applyBlur()办法中:

BlurViewModel.kt

internal fun applyBlur(blurLevel: Int) {
    workManager.enqueue(OneTimeWorkRequest.from(BlurWorker::class.jaga))
}

4.2.6、第6步 – 运转您的代码!

运转您的代码。此代码应进行编辑,而且在按下Go按钮时,您应该会看到告诉。请注意,如需检查更含糊的相片,您应该挑选“More blurred”或“the most blurred”选项。

使用WorkManager在后台处理工作 - Kotlin(上)

如需承认图片是否已成功含糊,您可以在Android Studio中翻开**设备文件浏览器**:

使用WorkManager在后台处理工作 - Kotlin(上)

然后顺次转到data > data > com.example.background > file > Blathfilterfilter_outputs >URI ,并承认纸杯蛋糕事实上现已含糊:

使用WorkManager在后台处理工作 - Kotlin(上)

## 五、增加输入和输出 对资源目录中的图片资源进行含糊处理当然不错,但假如想让O-M-Matic真实成为一款革命性的图片编辑运用,您应该让用户含糊处理他们在屏幕上看到的图片,然后向他们展示通过含糊处理的图片。

为实现此目标,咱们将供给作为输入显现在WorkRequest中的纸杯蛋糕图片的URI,然后运用WorkRequest的输入显现 最终的通过含糊处理的图片。

5.1、第1步 – 创立数据输入目标

输入和输出通过Data目标传入和传出。Data目标是轻量化的键值对容器。它们用于存储少数可从WorkRequest传入和传出的数据。

您需求将用户图片的URI传入捆绑包中。该URI存储在名为imageUri的变量中。

BlurViewModel中,创立一个名为createInputDataForUri的私有办法。该办法应履行以下操作:

  1. 创立一个Data.Builder目标。在收到恳求时,导入androidx.work.Data
  2. 假如imageUri对错nullURI,则运用putString办法将其增加到Data目标。该办法可获取一个键和一个值。您可以运用Constants类中的字符串常量KEY_IMAGE_URI
  3. Data.Builder目标调用build()以创立Data目标并回来。

下面是完好的createInputDataForUri办法:

BlurViewModel.kt

/**
 * Creates the input data bundle which includes the Uri to operate on
 * @return Data which contains the Image Uri as a String
 */
 private fun createInputDataForUri(): Data {
     val builder = Data.Builder()
     imageUri?.let {
         builder.putString(KEY_IMAGE_URI, imageUri.toString())
     }
     return builder.build()
 }

5.2、第2步 – 将数据目标传递到WorkRequest

您将更改BlurViewModel中的appluBlur办法,以便:

  1. 创立新的OneTimeWorkRequestBuilder
  2. 调用setInputData,传入createInputDataForUri的结果
  3. 构建OneTimeWorkRequest.
  4. 运用WorkManager将作业恳求参加行列,以便体系将可以依照预期运转作业。

下面是完好的applyBlur办法:

BlurViewModel.kt

internal fun applyBlue(blurLevel: Int) {
    val blurRequest = OneTimeWorkRequestBuilder<BlurWorker>()
        .setInputData(createInputDataForUri())
        .build()
    workManager.enqueue(blurRequest)
}

5.3、第3步 – 更新BlurWorker的doWork()以获取输入

现在,请更新BlurWorkerdoWork()办法,以获取从Data目标传入的URI:

BlurWorker.kt

override fun doWork(): Result {
    val appContext = applicationContext
    // ADD THIS LINE
    val resourceUri = inputData.getString(KEY_IMAGE_URI)
    // ... rest of doWork()
}

5.4、第4步 – 对指定URI进行含糊处理

有了此URI,咱们现在对屏幕上的纸杯蛋糕图片进行含糊处理。

  1. 移出之前用于获取图片资源的代码。 val picture = BitmapFactory.decodeResource(appContext.resources, R.drawable.android_cupcake)
  2. 检查以承认从传入的Data获取的resourceUri不为空。
  3. picture变量分配给传入的图片,如下所示: val picture = BitmapFactory.decodeStream(appContext.contentResolver.openInputStream(Uri.parse(resourceUri)))

BlurWork.kt

override fun doWork(): Result {
    val appContext = applicationContext
    val resourceUri = inputData.getString(KEY_IMAGE_URI)
    makeStatusNotification("Blurring image", appContext)
    return try {
        // REMOVE THIS
        // val picture = BitmapFactory.decodeResource(appContext.resources, R.drawable.android_cupcake)
        if (TextUtils.isEmpty(resourceUri)) {
            Log.e(TAG, "Invalid input uri")
            throw IllegalArgumentException("Invalid input uri")
        }
        val resolver = appContext.contentResolver
        val picture = BitmapFactory.decodeStream(resolver.openInputStream(Uri.parse(resourceUri)))
        val output = blurBitmap(picture, appContext)
        //Write bitmap to a temp file
        val outputUri = writeBitmapToFile(appContext, output)
        Result.success()
    } catch (throwable: Throwable) {
        Log.e(TAG, "Error appluing blur")
        throwable.printStackTrace()
        Result.failure()
    }
}

5.5、第5步 – 输出临时URI

此作业器的作业已完结,您可以在Result.success()中回来输出URI。供给作为输出数据的输出URI,以便其他作业器可以轻松拜访这张临时图片,履行进一步操作。

  1. 像对输入进行的操作一样,创立新的Data,并将outputUri存储为String。运用相同的键,即KEY_IMAGE_URI
  2. 运用Result.success(Data outputData)办法将它回来给WorkManager。

BlurWorker.ktdoWork()中的Result.success()行修改为:

val outputData = workDataOf(KEY_IMAGE_URI to outputUri.toString())
Result.success(outputData)

5.6、第6步 – 运转您的运用

此刻,您应该运转运用。它应该进行编译而且行为与您通过设备文件浏览器检查通过含糊处理的图片相同,只是图片尚未显现在屏幕上。

如需检查是否存在其他通过含糊处理的图片,您可以在Android Studio中翻开设备文件浏览器,然后转到data/data/com.example.background/files/blur_filter_outputs/<URI>,就像上一步的操作一样。

请注意,您或许需求点击Synchronize才干检查到图片:

使用WorkManager在后台处理工作 - Kotlin(上)