WorkManager的进阶

Advanced Concepts

Custom WorkManager Configuration and Initialization

默认情况下,当app启动的时候WorkManager自动的完成了配置,这个配置适用于大多数app.如果我们需要对WorkManager有更多的控制,比如:管理和调度任务,可以使用自己的配置初始化WorkManager.
这里有三种初始化的方式:

  1. Default initialization

    在应用启动的时候,WorkManager通过一个自定义的ContentProvider来初始化自己。相关代码在androidx.work.impl.WorkManagerInitializer中,同时使用默认的配置。除非你明确的禁止,否则默认的初始化将会自动完成。

    如果想要使用自己的配置,首先需要移除默认的初始化器。步骤如下:

移除默认初始化器

  1. Custom initialization
添加自定义配置
// provide custom configuration
Configuration myConfig = new Configuration.Builder()
    .setMinimumLoggingLevel(android.util.Log.INFO)
    .build();

//initialize WorkManager
WorkManager.initialize(this, myConfig);
  1. On-demand initialization(按需初始化)

Note: On-demand initialization is available in WorkManager 2.1.0-alpha01 and higher.
自定义初始化WorkManager是最灵活、合适的方式。这种方式允许你只有在需要的时候才初始化,而不是每次app启动的时候。这样,WorkManager的初始化就不在应用的启动配置列表中,优化了应用启动的性能。
实现步骤如下:

  1. 禁止默认的初始化器。
  2. 应用的Application实现Configuration.Provider 接口,并且重写getWorkManagerConfiguration()方法。
  3. 当我们需要使用WorkManager时,调用WorkManager.getInstance(Context)获取WorkManager对象。WorkManager会调用应用自定义的getWorkManagerConfiguration()方法去加载其配置。(我们不需要手动调用initialize())
    这里不要调用WorkManager.getInstance(),除非你确保WorkManager已经初始化完成
class MyApplication extends Application implements Configuration.Provider {
    @Override
    public Configuration getWorkManagerConfiguration() {
        return Configuration.Builder()
                .setMinimumLoggingLevel(android.util.Log.INFO)
                .build();
    }
}
Threading in WorkManager(WorkManager中的线程)

前面我们提到了WorkManager可以代替我们完成后台异步操作。基本实现可以满足大多数应用的需求。对于更高级别的使用案例,例如正确的处理被停止的工作任务,我们需要聊了解下WorkManager中的线程和并发。

WorkManager提供了四种工作场景:

  1. Worker ,是最简单的一个实现。前面我们已经有了大概的了解。WorkManager 自动地在一个后台线程中允许它。
  2. CoroutineWorker , 是针对Kotlin 的一种实现。CoroutineWorker后台任务暴露了一个suspending(可挂起)的方法。默认运行在一个默认的Dispatcher(可重写)中。
  3. RxWorker , 是针对RxJava2的用户设计的一个实现。
  4. ListenableWorker , 是Woker、CoroutineWorker、RxWorker的基类,它专门为使用异步回调的java开发者设计。
Threading in Worker

当我们使用一个Worker的时候,WorkManager自动地在一个后台线程调用doWork()方法,这个后台线程来源于WorkManager的配置中指定的一个线程池。默认情况,系统提供了一个默认的线程池给我们,但是我们可以自己指定使用的线程池。例如,共用已经存在的线程池、或者创建一个单线程线程池,以确保所有后台任务都顺序执行,或者仅仅是指定一个不同容量的线程池。指定自己的线程池,首先要确保已经允许了手动初始化WorkManager。配置WorkManager的时候,我们可以像下面这样指定线程池。

WorkManager.initialize(
    context,
    new Configuration.Builder()
        .setExecutor(Executors.newFixedThreadPool(8))
        .build());
public class DownloadWorker extends Worker {

    public DownloadWorker(Context context, WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public Result doWork() {
        for (int i = 0; i < 100; ++i) {
            if (isStopped()) {// 这里处理循环过程中停止任务,比如,条件突然不满足
                break;
            }

            try {
                downloadSynchronously("https://www.google.com");
            } catch (IOException e) {
                return Result.failure();
            }
        }

        return Result.success();
    }
}
Threading in CoroutineWorker

针对Kotlin用户,WorkManager提供了一等类支持coroutines。首选需要在gradle中配置相关依赖,上面已经详见上文。然后继承CoroutineWorker。下面是一个例子:

class CoroutineDownloadWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {

    override val coroutineContext = Dispatchers.IO

    override suspend fun doWork(): Result = coroutineScope {
        val jobs = (0 until 100).map {
            async {
                downloadSynchronously("https://www.google.com")
            }
        }

        // awaitAll will throw an exception if a download fails, which CoroutineWorker will treat as a failure
        jobs.awaitAll()
        Result.success()
    }
}

注意这里的CoroutineWorker.doWork() 是一个suspending(可挂起)方法。其中的方法,并不运行在配置中指定的线程池中。默认它运行在Dispatchers.Default中,通过提供CoroutineContext我们可以指定自己的Dispatchers。如上面代码所示。

CoroutineWorker通过取消coroutine和生成取消信号自动的处理停止任务,我们无需做任何额外的额操作。

Threading in RxWorker

系统提供了WorkManager和RxJava2之间相互操作的方法。首先需要在gradle中配置相关依赖,详见上文。然后继承RxWorker,最后重写createWork()方法,这个方法返回一个Single代表着执行的结果。下面是个例子:

public class RxDownloadWorker extends RxWorker {

    public RxDownloadWorker(Context context, WorkerParameters params) {
        super(context, params);
    }

    @Override
    public Single createWork() {
        return Observable.range(0, 100)
            .flatMap { download("https://www.google.com") }
            .toList()
            .map { Result.success() };
    }
}

注意RxWorker.createWork()在主线程中调用,但是返回的值默认在后台线程中订阅。我们可以重写RxWorker.getBackgroundScheduler()改变订阅线程。

停止一个RxWorker系统会自动妥善的处理Observers,我们无需做任何额外操作。

Threading in ListenableWorker

一定会有一个场景,我们需要提供一个线程策略。比如:我们也许需要处理一个异步的回调操作,很明显我们不能仅仅指望一个Worker,因为它不支持代码块阻塞。WorkManager通过提供ListenableWorker支持这种案例。ListenableWorker是最低级别的worker API;Worker、CoroutineWorker和RxWorker 都是源自这个类。ListenableWorker仅提供任务需要开始和结束的标识,线程完全由我们自己来控制。开始任务的标识是在主线程执行的,所以我们手动选择执行在后台线程很重要。

抽象方法ListenableWorker.startWork() 返回一个Result的ListenableFuture。ListenableFuture是一个轻量级的接口;它是一个提供附着监听并且处理异常的Future。当后台操作完成时该方法返回一个带有结果的ListenableFuture。我们可以通过以下2个方法中的一个创建ListenableFutures。

  1. 如果使用的是Guava,使用ListeningExecutorService
  2. 在gradle中配置相关依赖,并且使用CallbackToFutureAdapter。
    当任务停止时,ListenableFuture也要跟着取消,我们可以简单的添加一个取消监听
    下面是个例子:
public class CallbackWorker extends ListenableWorker {

    public CallbackWorker(Context context, WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public ListenableFuture startWork() {
        return CallbackToFutureAdapter.getFuture(completer -> {
            Callback callback = new Callback() {
                int successes = 0;

                @Override
                public void onFailure(Call call, IOException e) {
                    completer.setException(e);
                }

                @Override
                public void onResponse(Call call, Response response) {
                    ++successes;
                    if (successes == 100) {
                        completer.set(Result.success());
                    }
                }
            };

            completer.addCancellationListener(cancelDownloadsRunnable, executor);// 添加一个取消监听

            for (int i = 0; i < 100; ++i) {
                downloadAsynchronously("https://www.google.com", callback);
            }
            return callback;
        });
    }
}

你可能感兴趣的:(android,WorkManager,官网文档梳理,官网api)