Android WorkManager,看这一篇就够了

 

1.简介

Android上有许多可延期的后台工作选项。此代码实验室涵盖WorkManager,这是一个可延迟的后台工作的兼容,灵活且简单的库。WorkManager是Android上推荐的任务调度框架,用于可延缓的工作,并且可以执行。

1.1 什么是WorkManager

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

WorkManager是一个简单但非常灵活的库,它具有许多其他优点。这些包括:

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

1.2 何时使用WorkManager

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

可以很好地使用WorkManager的一些任务示例:

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

WorkManager提供有保证的执行,但并非所有任务都需要执行。因此,这不是将所有任务从主线程中运行掉的万能方法。有关何时使用WorkManager的更多详细信息,请参阅《后台处理指南》。

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

2.将WorkManager添加到您的应用程序

WorkManager需要下面的gradle依赖项。这些已包含在构建文件中:

app / build.gradle

dependencies {
    // Other dependencies
    implementation "androidx.work:work-runtime:$versions.work"
}

您应该work-runtime从此处获取最新版本,然后输入正确的版本。目前,最新版本为:

build.gradle

versions.work = "2.3.3"

如果您将版本更新为较新的版本,请确保立即同步以将项目与更改的gradle文件同步。

2.1 WorkManager基础

您需要了解一些WorkManager类:

  • Worker:在此处将要执行的实际工作的代码放在后台。您将扩展此类并重写doWork()方法。
  • WorkRequest这表示需要做一些工作。您将在Worker创建的过程中将自己的信息传递给WorkRequest。制作时,WorkRequest您还可以指定类似Constraints何时Worker运行的内容。
  • WorkManager此类实际上是安排您的WorkRequest并使其运行。它以分散系统资源负载的方式调度WorkRequest,同时遵守您指定的约束。

2.2 创建步骤

第一步:创建BlurWorker 扩展自Worker

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.util.Log;

import com.example.background.R;

import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

public class BlurWorker extends Worker {
    public BlurWorker(
            @NonNull Context appContext,
            @NonNull WorkerParameters workerParams) {
        super(appContext, workerParams);
    }

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

    @NonNull
    @Override
    public Result 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 Result.success();
        } catch (Throwable throwable) {

            // Technically WorkManager will return Result.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 Result.failure();
        }
    }
}

第二步:在ViewModel中获取WorkManager

在中为WorkManager实例创建变量,ViewModel并在ViewModel的构造函数中实例化该变量:

private WorkManager mWorkManager;

// BlurViewModel constructor
public BlurViewModel(@NonNull Application application) {
  super(application);
  mWorkManager = WorkManager.getInstance(application);

  //...rest of the constructor
}

第三步:在WorkManager中排队工作请求

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

  • OneTimeWorkRequest:WorkRequest只会执行一次的A。
  • PeriodicWorkRequest:WorkRequest一个周期将重复的A。

我们只希望单击“ 转到”按钮时使图像模糊一次。单击“ applyBlur执行按钮时将调用该方法,因此请OneTimeWorkRequestBlurWorker此处创建一个。然后,使用您的WorkManager实例将您的WorkRequest.

将以下代码行添加到BlurViewModel的applyBlur()方法中:

BlurViewModel.java

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

第四步:添加输入和输出

  1. 第1步-创建数据输入对象
  2. 将数据对象传递给WorkRequest
  3. 更新BlurWorker的doWork()以获取输入
  4. 输出临时URI

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

/**
 *  创建包含Uri的输入数据
 * @return Data类,包含Uri的字符串
 */
private Data createInputDataForUri() {
    Data.Builder builder = new Data.Builder();
    if (mImageUri != null) {
        builder.putString(KEY_IMAGE_URI, mImageUri.toString());
    }
    return builder.build();
}

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

   mWorkManager.enqueue(blurRequest);
}

更新BlurWorkerdoWork()方法,以获取从Data对象传递来的URI :

public Result doWork() {

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

我们已经完成了此Worker的工作,现在可以返回Result.success()。我们将提供OutputURI作为输出数据。

Data outputData = new Data.Builder()
    .putString(KEY_IMAGE_URI, outputUri.toString())
    .build();
return Result.success(outputData);

3.链式工作

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

 

Android WorkManager,看这一篇就够了_第1张图片

一个链接的输出WorkRequest成为链接中下一链接的输入WorkRequest。各个WorkRequest彼此之间传递的输入和输出,并在上图中显示为蓝色部分的文本。

现在不是通过WorkManager.enqueue()来发送请求,而是调用WorkManager.beginWith(),它放回WorkContinuation类,用来定义工作请求链。

// Example code. Don't copy to the project
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 

4.确保单独的工作

如果您一次只希望运行一个工作链,您可以使用beginUniqueWork代替beginWith;

确保模糊文件的工作链是唯一的beginUniqueWork。传递IMAGE_MANIPULATION_WORK_NAME作为密钥。您还需要传递ExistingWorkPolicy。你的选择是REPLACEKEEP或者APPEND

WorkContinuation continuation = mWorkManager
                .beginUniqueWork(IMAGE_MANIPULATION_WORK_NAME,
                       ExistingWorkPolicy.REPLACE,
                       OneTimeWorkRequest.from(CleanupWorker.class));

5.添加请求标签和显示工作状态

您将使用标签来标记您的工作,而不是使用WorkManager ID

OneTimeWorkRequest save = new OneTimeWorkRequest.Builder(SaveImageToFileWorker.class)
        .addTag(TAG_OUTPUT) // This adds the tag
        .build();

5.1 获取WorkInfo

// New instance variable for the WorkInfo class
private LiveData> mSavedWorkInfo;

// Placed this code in the BlurViewModel constructor
mSavedWorkInfo = mWorkManager.getWorkInfosByTagLiveData(TAG_OUTPUT);  

// Add a getter method for mSavedWorkInfo
LiveData> getOutputWorkInfo() { return mSavedWorkInfo; } 

5.2 显示WorkInfo 

使用以下workInfo.getState().isFinished()检查工作状态是否已完成 ;

// Show work status, added in onCreate()
mViewModel.getOutputWorkInfo().observe(this, listOfWorkInfos -> {

    // If there are no matching work info, do nothing
    if (listOfWorkInfos == null || listOfWorkInfos.isEmpty()) {
        return;
    }

    // We only care about the first output status.
    // Every continuation has only one worker tagged TAG_OUTPUT
    WorkInfo workInfo = listOfWorkInfos.get(0);

    boolean finished = workInfo.getState().isFinished();
    if (!finished) {
        showWorkInProgress();
    } else {
        showWorkFinished();
    }
});

6.取消工作

您可以使用ID,标签和唯一链名取消工作。

void cancelWork() {
    mWorkManager.cancelUniqueWork(IMAGE_MANIPULATION_WORK_NAME);
}

 

 

 

你可能感兴趣的:(Android,android)