WorkManager 的使用

背景使用WorkManager

 

1。介绍

Android上有许多选项可用于延迟后台工作。此代码库涵盖了WorkManager,这是一个兼容,灵活且简单的库,用于可延迟的后台工作。WorkManager目前处于alpha状态 - 稳定后,它将成为Android上推荐的任务调度程序。

什么是WorkManager

WorkManager是Android Jetpack的一部分,是后台工作的架构组件,需要机会主义和有保证的执行相结合。机会执行意味着WorkManager将尽快完成后台工作。保证执行意味着WorkManager将负责在各种情况下开始工作的逻辑,即使您离开应用程序也是如此。

WorkManager是一个简单但非常灵活的库,具有许多额外的好处。这些包括:

  • 支持异步一次性和定期任务
  • 支持网络条件,存储空间和计费状态等约束
  • 链接复杂的工作请求,包括并行运行工作
  • 一个工作请求的输出用作下一个的输入
  • 将API级别兼容性处理回API级别14(请参阅注释)
  • 使用或不使用Google Play服务
  • 遵循系统健康最佳实践
  • LiveData支持,可在UI中轻松显示工作请求状态

注意:

WorkManager中坐了几个API,例如顶部JobSchedulerFirebaseJobDispatcherAlarmManager。WorkManager根据用户的设备API级别以及设备是否可以访问Google Play服务等条件,选择要使用的API。要了解更多信息,请查看WorkManager文档

何时使用WorkManager

即使用户离开特定屏幕或您的应用程序,WorkManager库也是完成有用任务的不错选择。

一些充分利用WorkManager的任务示例:

  • 上传日志
  • 将滤镜应用于图像并保存图像
  • 定期将本地数据与网络同步

WorkManager提供有保证的执行,并非所有任务都需要。因此,从主线程运行每个任务并不是一件容易的事。有关何时使用WorkManager的更多详细信息,请查看后台处理指南

你将建立什么

如今,智能手机几乎擅长拍照。摄影师可以拍摄一些神秘的可疑模糊照片的日子已经一去不复返了。

在这个代码框中,你将使用Blur-O-Matic,一个模糊照片和图像并将结果保存到文件的应用程序。那是尼斯湖水怪还是玩具潜艇?有了Blur-O-Matic,没有人会知道。

5b2a35a2bd047693.pnguploading.4e448015.gif正在上传…重新上传取消

fcb326118dd99959.pnguploading.4e448015.gif正在上传…重新上传取消

你将学到什么

  • 将WorkManager添加到项目中
  • 安排一个简单的任务
  • 输入和输出参数
  • 链接工作
  • 独特的工作
  • 在UI中显示工作状态
  • 取消工作
  • 工作限制

你需要什么

 

2。设置好

第1步 - 下载代码

单击以下链接下载此codelab的所有代码:

下载起始代码

或者如果您愿意,可以从GitHub克隆导航codelab:

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

第2步 - 获取图像

如果您使用的设备已经下载或在设备上拍照,那么您已经完成了设置。

如果您使用的是全新设备(如最近创建的模拟器),则需要使用设备从网络上拍照或下载图像。选择一些神秘的东西!

第3步 - 运行应用程序


您可以选择一个图像并进入下一个屏幕,该屏幕上有单选按钮,您可以在其中选择您希望图像模糊的程度。按“执行按钮将模糊并保存图像。

截至目前,该应用程序不适用任何模糊。

起始代码包含:

  • WorkerUtils此类包含实际模糊的代码,以及一些便于稍后用于显示Notifications和减慢应用程序的便捷方法。
  • BlurActivity***:显示图像的活动,包括用于选择模糊等级的单选按钮。
  • BlurViewModel***:此视图模型存储显示所需的所有数据BlurActivity。它也是使用WorkManager启动后台工作的类。
  • Constants一个静态类,包含一些在codelab中使用的常量。
  • SelectImageActivity允许您选择图像的第一个活动。
  • res/activity_blur.xmlres/activity_select.xml:每个活动的布局文件。

***这些是您编写代码的唯一文件。

 

 

 

3。将WorkManager添加到您的应用程序

WorkManager需要下面的gradle依赖。继续,现在添加它:

应用程序/的build.gradle

dependencies {
    // Other dependencies
    implementation "android.arch.work:work-runtime:CURRENT_VERSION"
}

你应该work-runtime这里获得最新版本。

确保立即同步以将项目与更改的gradle文件同步。

 

4。进行第一次WorkRequest

在此步骤中,您将在所res/drawable调用的文件夹中拍摄图像,test.jpg并在后台运行一些函数。这些功能会使图像模糊并将其保存到临时文件中。

WorkManager基础知识

您需要了解一些WorkManager类:

  • Worker:这是您在后台执行要执行的实际工作的代码的位置。您将扩展此类并覆盖该doWork()方法。
  • WorkRequest这代表了做一些工作的请求。Worker作为创建你的一部分,你会传入你的WorkRequest。使得当WorkRequest你还可以指定喜欢的东西Constraints时,就Worker应该运行。
  • WorkManager这个课程实际上安排你的WorkRequest并让它运行。它WorkRequest以一种分散系统资源负载的方式调度s,同时遵守您指定的约束。

在您的情况下,您将定义一个新的BlurWorker,其中包含模糊图像的代码。单击“ Go”按钮时,将WorkRequest创建a,然后将其排入WorkManager

第1步 - 制作BlurWorker

在包中workers,创建一个名为的新类BlurWorker

它应该延伸Worker

第2步 - 覆盖并实现doWork()

你的Worker意志会模糊res/test.jpg图像。

重写该doWork()方法,然后执行以下操作:

  1. 获得Context通过调用getApplicationContext()。您将需要这个用于您将要执行的各种位图操作。
  2. Bitmap从测试图像创建一个:
Bitmap picture = BitmapFactory.decodeResource(
    applicationContext.getResources(),
    R.drawable.test);
  1. 通过调用静态blurBitmap方法获取位图的模糊版本WorkUtils
  2. 通过调用静态writeBitmapToFile方法将该位图写入临时文件WorkUtils。确保将返回的URI保存到本地变量。
  3. 通过调用静态makeStatusNotification方法创建显示URI的通知WorkUtils
  4. 返回WorkerResult.SUCCESS
  5. 在try / catch语句中包含步骤2-6中的代码。抓住一个通用的Throwable
  6. 在catch语句中,发出错误的Log语句: Log.e(TAG, "Error applying blur", throwable);
  7. 在catch语句中然后返回 WorkerResult.FAILURE;

完成此步骤的代码如下。

BlurWorker.java

public class BlurWorker extends Worker {

    private static final String TAG = BlurWorker.class.getSimpleName();

    @NonNull
    @Override
    public WorkerResult doWork() {

        Context applicationContext = getApplicationContext();

        try {

            Bitmap picture = BitmapFactory.decodeResource(
                    applicationContext.getResources(),
                    R.drawable.test);
        
            // Blur the bitmap
            Bitmap output = WorkerUtils.blurBitmap(picture, applicationContext);

            // Write bitmap to a temp file
            Uri outputUri = WorkerUtils.writeBitmapToFile(applicationContext, output);

            WorkerUtils.makeStatusNotification("Output is "
                  + outputUri.toString(), applicationContext);

            // If there were no errors, return SUCCESS
            return WorkerResult.SUCCESS;
        } catch (Throwable throwable) {

            // Technically WorkManager will return WorkerResult.FAILURE
            // but it's best to be explicit about it.
            // Thus if there were errors, we're return FAILURE
            Log.e(TAG, "Error applying blur", throwable);
            return WorkerResult.FAILURE;
        }

第3步 - 在ViewModel中获取WorkManager

WorkManager您的实例创建一个变量,ViewModel并在其ViewModel构造函数中实例化它:

BlurViewModel.java

private WorkManager mWorkManager;

// BlurViewModel constructor
public BlurViewModel() {
  mWorkManager = WorkManager.getInstance();
  //...rest of the constructor
}

第4步 - 在WorkManager中将WorkRequest排入队列

好的,是时候做一个WorkRequest并告诉WorkManager运行它。有两种类型的WorkRequests:

  • OneTimeWorkRequest:WorkRequest只会执行一次的A.
  • PeriodicWorkRequest:WorkRequest将在循环中重复。

我们只希望在单击Go按钮时图像模糊一次。单击Go按钮applyBlur时会调用该方法,因此从那里创建一个。然后,使用您的实例将您的实例排入队列OneTimeWorkRequestBlurWorkerWorkManagerWorkRequest.

BlurViewModel.java

void applyBlur(int blurLevel) {
   mWorkManager.enqueue(OneTimeWorkRequest.from(BlurWorker.class));
}

第5步 - 运行你的代码!

运行你的代码。它应该编译,当你按下Go按钮时你应该看到Notification 。

 


您可以选择在Android Studio中打开设备文件资源管理器

 

然后导航到data> data> com.example.background> files> blur_filter_outputs> <URI>并确认鱼实际上是模糊的:

 

 

 

 

5。添加输入和输出

模糊测试图像一切都很好,但是对于Blur-O-Matic真正成为革命性的图像编辑应用程序而言,它需要让用户模糊自己的图像。

为此,我们将提供用户所选图像的URI作为我们的输入WorkRequest

第1步 - 创建数据输入对象

输入和输出通过Data对象传入和传出。Data对象是键/值对的轻量级容器。他们是为了存储数据量,可能通过进入和离开WorkRequest秒。

您将要将用户图像的URI传递到一个包中。该URI存储在一个名为的变量中mImageUri

创建一个名为的私有方法createInputDataForUri。这种方法应该:

  1. 创建一个Data.Builder对象。
  2. 如果mImageUri是非null URI,则Data使用该putString方法将其添加到对象。此方法采用键和值。您可以使用字符串常量KEY_IMAGE_URIConstants类。
  3. 调用build()Data.Builder的对象,使您的Data对象,并将其返回。

以下是完整的createInputDataForUri方法:

BlurViewModel.java

/**
 * Creates the input data bundle which includes the Uri to operate on
 * @return Data which contains the Image Uri as a String
 */
private Data createInputDataForUri() {
    Data.Builder builder = new Data.Builder();
    if (mImageUri != null) {
        builder.putString(KEY_IMAGE_URI, mImageUri.toString());
    }
    return builder.build();
}

第2步 - 将Data对象传递给WorkRequest

您将要更改applyBlur方法,以便:

  1. 创建一个新的OneTimeWorkRequest.Builder
  2. 调用setInputData,传递结果createInputDataForUri
  3. 建立OneTimeWorkRequest
  4. 排队请求使用WorkManager

以下是完整的applyBlur方法:

BlurViewModel.java

void applyBlur(int blurLevel) {
   OneTimeWorkRequest blurRequest =
                new OneTimeWorkRequest.Builder(BlurWorker.class)
                        .setInputData(createInputDataForUri())
                        .build();

   mWorkManager.enqueue(blurRequest);
}

第3步 - 更新BlurWorker的doWork()以获取输入

现在让我们更新BlurWorkerdoWork()方法来获取我们从Data对象传入的URI :

BlurWorker.java

public WorkerResult doWork() {

        Context applicationContext = getApplicationContext();
        
        // ADD THIS LINE
       String resourceUri = getInputData().getString(Constants.KEY_IMAGE_URI, null);
         
        //... rest of doWork()
}

第4步 - 模糊给定的URI

使用URI,您可以模糊用户选择的图像:

BlurWorker.java

public WorkerResult doWork() {
    String resourceUri = getInputData().getString(Constants.KEY_IMAGE_URI, null);
    Context applicationContext = getApplicationContext();

    try {

        // REPLACE THIS CODE:
        // Bitmap picture = BitmapFactory.decodeResource(
        //        applicationContext.getResources(),
        //        R.drawable.test);
        // WITH
        if (TextUtils.isEmpty(resourceUri)) {
            Log.e(TAG, "Invalid input uri");
            throw new IllegalArgumentException("Invalid input uri");
        }

        ContentResolver resolver = applicationContext.getContentResolver();
        // Create a bitmap
        Bitmap picture = BitmapFactory.decodeStream(
                resolver.openInputStream(Uri.parse(resourceUri)));
        //...rest of doWork

第5步 - 输出临时URI

你还没有使用它,但是让我们继续为我们模糊照片的临时URI 提供输出数据。去做这个:

  1. Data像输入一样创建一个新的,并存储outputUriString。使用相同的密钥KEY_IMAGE_URI
  2. 通过这个来WorkersetOutputData方法。

BlurWorker.java

setOutputData(new Data.Builder().putString(
                    Constants.KEY_IMAGE_URI, outputUri.toString()).build());

第5步 - 运行您的应用

此时你应该运行你的应用程序。它应该编译并具有相同的行为。

(可选)您可以在Android Studio中打开设备文件资源管理器,然后导航到 数据> data> com.example.background> files> blur_filter_outputs> <URI>,就像在上一步中一样。

请注意,您可能需要同步才能查看图片:

 

做得好!您使用了模糊输入图像WorkManager

 

 

6。连接你的工作

现在你正在完成一项工作任务:模糊图像。这是一个很好的第一步,但缺少一些核心功能:

  • 它不会清理临时文件。
  • 它实际上并不将图像保存为永久文件。
  • 它总是模糊图片相同的数量。

我们将使用WorkManager工作链来添加此功能。

WorkManager允许您创建WorkerRequest按顺序或并行运行的单独s。在此步骤中,您将创建一个如下所示的工作链:

 

所述WorkRequests的表示为方框。

链接的另一个非常巧妙的特征是一个输出WorkRequest成为WorkRequest链中下一个的输入。在每个之间传递的输入和输出WorkRequest显示为蓝色文本。

第1步 - 创建清理并保存工人

首先,您将定义所需的所有Worker类。您已经有一个Worker模糊图像,但您还需要一个Worker清理临时文件和Worker永久保存图像的文件。

worker包中创建两个扩展的新类Worker

第一个应该被调用CleanupWorker,第二个应该被调用SaveImageToFileWorker

第2步 - 覆盖并实现CleanupWorker的doWork()

CleanupWorker不需要任何输入或传递任何输出。它总是删除临时文件(如果存在)。因为这不是关于文件操作的代码库,所以您可以复制以下代码CleanupWorker

CleanupWorker.java

public class CleanupWorker extends Worker {
    private static final String TAG = CleanupWorker.class.getSimpleName();

    @NonNull
    @Override
    public WorkerResult doWork() {
        Context applicationContext = getApplicationContext();
        
        try {
            File outputDirectory = new File(applicationContext.getFilesDir(),
                    Constants.OUTPUT_PATH);
            if (outputDirectory.exists()) {
                File[] entries = outputDirectory.listFiles();
                if (entries != null && entries.length > 0) {
                    for (File entry : entries) {
                        String name = entry.getName();
                        if (!TextUtils.isEmpty(name) && name.endsWith(".png")) {
                            boolean deleted = entry.delete();
                            Log.i(TAG, String.format("Deleted %s - %s",
                                    name, deleted));
                        }
                    }
                }
            }

            return WorkerResult.SUCCESS;
        } catch (Exception exception) {
            Log.e(TAG, "Error cleaning up", exception);
            return WorkerResult.FAILURE;
        }
    }
} 

第3步 - 覆盖并实现SaveImageToFileWorker的doWork()

SaveImageToFileWorker将采取输入和输出。输入是String与密钥一起存储的KEY_IMAGE_URI。输出也将String与密钥一起存储KEY_IMAGE_URI

 

由于这仍然不是关于文件操作的代码库,因此代码如下,有两个TODO用于填写适当的输入和输出代码的代码。这与您在输入和输出的最后一步中编写的代码非常相似(它使用所有相同的键)。

SaveImageToFileWorker.java

public class SaveImageToFileWorker extends Worker {
    private static final String TAG = SaveImageToFileWorker.class.getSimpleName();

    private static final String TITLE = "Blurred Image";
    private static final SimpleDateFormat DATE_FORMATTER =
            new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss z", Locale.getDefault());

    @NonNull
    @Override
    public WorkerResult doWork() {
        Context applicationContext = getApplicationContext();

        ContentResolver resolver = applicationContext.getContentResolver();
        try {
            String resourceUri = // TODO get the input Uri from the Data object
            Bitmap bitmap = BitmapFactory.decodeStream(
                   resolver.openInputStream(Uri.parse(resourceUri)));
            String imageUrl = MediaStore.Images.Media.insertImage(
                    resolver, bitmap, TITLE, DATE_FORMATTER.format(new Date()));
            if (TextUtils.isEmpty(imageUrl)) {
                Log.e(TAG, "Writing to MediaStore failed");
                return WorkerResult.FAILURE;
            }
            // TODO create and set the output Data object with the imageUri.
            return WorkerResult.SUCCESS;
        } catch (Exception exception) {
            Log.e(TAG, "Unable to save image to Gallery", exception);
            return WorkerResult.FAILURE;
        }
    }
}

第4步 - 创建WorkRequest链

您需要修改BlurViewModelapplyBlur方法来执行的链条WorkRequest!而非只有一个。目前代码如下所示:

BlurViewModel.java

OneTimeWorkRequest blurRequest =
     new OneTimeWorkRequest.Builder(BlurWorker.class)
             .setInputData(createInputDataForUri())
             .build();

mWorkManager.enqueue(blurRequest);

而不是打电话WorkManager.enqueue(),打电话WorkManager.beginWith()。这返回a WorkContinuation,它定义了一个WorkRequests 链。您可以通过调用添加到这个链条的工作请求的then()方法,例如,如果有三个WorkRequest对象,workAworkB,和workC,你可以做到以下几点:

WorkContinuation continuation = mWorkManager.beginWith(workA);

continuation.then(workB) // FYI, then() returns a new WorkContinuation instance
        .then(workC)
        .enqueue(); // Enqueues the WorkContinuation which is a chain of work 
这将生成并运行以下WorkRequests链:

 

创建的一个链条CleanupWorker WorkRequest,一个BlurImage WorkRequestSaveImageToFileWorkRequestapplyBlur。将输入传递到BlurImage WorkRequest

代码如下:

BlurViewModel.java

void applyBlur(int blurLevel) {

    // Add WorkRequest to Cleanup temporary images
    WorkContinuation continuation =
        mWorkManager.beginWith(OneTimeWorkRequest.from(CleanupWorker.class));

    // Add WorkRequest to blur the image
    OneTimeWorkRequest blurRequest = new OneTimeWorkRequest.Builder(BlurWorker.class)
                    .setInputData(createInputDataForUri())
                    .build();
    continuation = continuation.then(blurRequest);


    // Add WorkRequest to save the image to the filesystem
    OneTimeWorkRequest save =
        new OneTimeWorkRequest.Builder(SaveImageToFileWorker.class)
            .build();
    continuation = continuation.then(save);

    // Actually start the work
    continuation.enqueue();
}

这应该编译运行。您应该能够看到您选择的任何图像现在模糊保存在图片文件夹中:

 

第5步 - 重复BlurWorker

是时候添加模糊图像的能力不同了。获取blurLevel传入的参数applyBlur并将许多模糊WorkRequest操作添加到链中。只有第一个WorkRequest需要并且应该接受uri输入。

请注意,这有点用于学习目的。将三次调用我们的模糊代码的效率低于BlurWorker控制模糊“级别”的输入。但这是一个很好的做法,并显示了WorkManager链的灵活性。

亲自尝试,然后与下面的代码进行比较:

BlurViewModel.java

void applyBlur(int blurLevel) {

    // Add WorkRequest to Cleanup temporary images
    WorkContinuation continuation = mWorkManager.beginWith(OneTimeWorkRequest.from(CleanupWorker.class));

    // Add WorkRequests to blur the image the number of times requested
    for (int i = 0; i < blurLevel; i++) {
        OneTimeWorkRequest.Builder blurBuilder =
                new OneTimeWorkRequest.Builder(BlurWorker.class);

        // Input the Uri if this is the first blur operation
        // After the first blur operation the input will be the output of previous
        // blur operations.
        if ( i == 0 ) {
            blurBuilder.setInputData(createInputDataForUri());
        }

        continuation = continuation.then(blurBuilder.build());
    }

    // Add WorkRequest to save the image to the filesystem
    OneTimeWorkRequest save = new OneTimeWorkRequest.Builder(SaveImageToFileWorker.class)
            .build();
    continuation = continuation.then(save);

    // Actually start the work
    continuation.enqueue();
}
精湛的“工作”!现在,您可以根据需要尽可能多地模糊图像!多神秘啊!

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值