在第4部分中使用Workmanager

Welcome to the fourth post of our WorkManager series.

欢迎来到我们的WorkManager系列的第四篇文章。

In this blog post, I’ll cover:

在此博客文章中,我将介绍:

  1. Custom Work Manager configuration with Types of Worker classes

    具有Worker类类型的Custom Work Manager配置
  2. Work Manager Threading

    工作管理器线程

1.自定义WorkManager配置 (1. Custom WorkManager Configuration)

By default, WorkManager configures itself automatically when your app starts, using reasonable options that are suitable for most apps. If you require more control of how WorkManager manages and schedules work, you can customize the WorkManager configuration by initializing WorkManager yourself.

默认情况下,WorkManager会使用适合大多数应用程序的合理选项自动在您的应用程序启动时自动配置自身。 如果您需要对WorkManager的管理方式和日程安排进行更多控制,则可以通过自己初始化WorkManager来自定义WorkManager配置。

1.1 WorkManager 2.1.0及更高版本 (1.1 WorkManager 2.1.0 and later)

WorkManager 2.1.0 has multiple ways to configure WorkManager. The most flexible way to provide a custom initialization for WorkManager is to use on-demand initialization, available in WorkManager 2.1.0 and later. The other options are discussed later.

WorkManager 2.1.0具有多种配置WorkManager的方法。 为WorkManager提供自定义初始化的最灵活的方法是使用WorkManager 2.1.0和更高版本中提供的按需初始化 。 其他选项将在后面讨论

按需初始化 (On-Demand Initialization)

On-demand initialization lets you create WorkManager only when that component is needed, instead of every time the app starts up. Doing so moves WorkManager off your critical startup path, improving app startup performance. To use on-demand initialization:

按需初始化使您仅在需要该组件时才创建WorkManager,而不必在每次启动应用程序时创建。 这样做会使WorkManager脱离关键的启动路径,从而提高了应用程序的启动性能。 要使用按需初始化:

删除默认的初始化程序 (Remove the default initializer)

To provide your own configuration, you must first remove the default initializer. To do so, update AndroidManifest.xml using the merge rule tools:node="remove":

要提供自己的配置,必须首先删除默认的初始化程序。 为此,请使用合并规则tools:node="remove"更新AndroidManifest.xml tools:node="remove"

<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
tools:node="remove" />

To learn more about using merge rules in your manifest, see the documentation on merging multiple manifest files.

要了解有关在清单中使用合并规则的更多信息,请参阅有关合并多个清单文件的文档

实施Configuration.Provider (Implement Configuration.Provider)

Have your Application class implement the Configuration.Provider interface, and providing your own implementation of Configuration.Provider.getWorkManagerConfiguration().

让您的Application类实现Configuration.Provider接口,并提供自己的Configuration.Provider.getWorkManagerConfiguration()

When you need to use WorkManager, make sure to call the method WorkManager.getInstance(Context). WorkManager calls your app's custom getWorkManagerConfiguration() method to discover its Configuration. (You do not need to call WorkManager.initialize() yourself.)

当您需要使用WorkManager时,请确保调用方法WorkManager.getInstance(Context) 。 WorkManager调用应用程序的自定义getWorkManagerConfiguration()方法以发现其Configuration 。 (您不需要自己调用WorkManager.initialize() 。)

Note: If you call the deprecated no-parameter WorkManager.getInstance() method before WorkManager has been initialized, the method throws an exception. You should always use the WorkManager.getInstance(Context) method, even if you're not customizing WorkManager.

注意:如果在初始化WorkManager之前调用不推荐使用的无参数WorkManager.getInstance()方法,则该方法将引发异常。 即使不自定义WorkManager,也应始终使用WorkManager.getInstance(Context)方法。

Here’s an example of a custom getWorkManagerConfiguration() implementation:

这是一个自定义getWorkManagerConfiguration()实现的示例:

class MyApplication() : Application(), Configuration.Provider {
override fun getWorkManagerConfiguration() =
Configuration.Builder()
.setMinimumLoggingLevel(android.util.Log.INFO)
.build()
}

WorkManager 2.0.1及更早版本 (WorkManager 2.0.1 and earlier)

For older versions of WorkManager, there are two initialization options:

对于旧版本的WorkManager,有两个初始化选项:

Default initialization

默认初始化

In most cases, the default initialization is all you need.

在大多数情况下,您只需要默认的初始化即可。

Custom initialization

自定义初始化

For more precise control of WorkManager, you can specify your own configuration.

为了更精确地控制WorkManager,您可以指定自己的配置。

默认初始化 (Default initialization)

WorkManager uses a custom ContentProvider to initialize itself when your app starts. This code lives in the internal class. androidx.work.impl.WorkManagerInitialize, and uses the default Configuration. The default initializer is automatically used unless you explicitly disable it. The default initializer is suitable for most apps.

应用程序启动时,WorkManager使用自定义的ContentProvider进行初始化。 此代码位于内部类中。 androidx.work.impl.WorkManagerInitialize ,并使用默认的Configuration 。 除非您明确禁用它,否则将自动使用默认的初始化程序。 默认的初始化程序适用于大多数应用程序。

自定义初始化 (Custom initialization)

If you want to control the initialization process, you must disable the default initializer, then define your own custom configuration.

如果要控制初始化过程,则必须禁用默认的初始化程序 ,然后定义自己的自定义配置。

Once the default initializer is removed, you can manually initialize WorkManager:

删除默认的初始化程序后,您可以手动初始化WorkManager:

// provide custom configuration
val myConfig = Configuration.Builder()
.setMinimumLoggingLevel(android.util.Log.INFO)
.build()
// initialize WorkManager
WorkManager.initialize(this, myConfig)

the WorkManager singleton. Make sure the initialization runs either in Application.onCreate() or in a ContentProvider.onCreate().

WorkManager单例。 确保初始化在Application.onCreate()ContentProvider.onCreate()

2.使用Kotlin的Work Manager线程 (2. Work Manager Threading with Kotlin)

2.1穿入工人 (2.1 Threading in Worker)

When you use a Worker, WorkManager automatically calls Worker.doWork() on a background thread. The background thread comes from the Executor specified in WorkManager's Configuration. By default, WorkManager sets up an Executor for you - but you can also customize your own. For example, you can share an existing background Executor in your app, or create a single-threaded Executor to make sure all your background work executes serially, or even specify a ThreadPool with a different thread count. To customize the, make sure you have enabled manual initialization of WorkManager. When configuring WorkManager, you can specify your Executor as follows:

使用Worker ,WorkManager会在后台线程上自动调用Worker.doWork() 。 后台线程来自WorkManager的Configuration指定的Executor 。 默认情况下,WorkManager会为您设置一个Executor -但您也可以自定义自己的执行器。 例如,您可以在您的应用程序中共享现有的后台Executor ,或者创建单线程Executor以确保您的所有后台工作都按顺序执行,甚至可以指定具有不同线程数的ThreadPool 。 要进行自定义,请确保已启用WorkManager的手动初始化 。 配置WorkManager时,可以按以下方式指定Executor

WorkManager.initialize(
context,
Configuration.Builder()
.setExecutor(Executors.newFixedThreadPool(8))
.build())

Here is an example of a simple Worker that downloads the content of some websites sequentially:

这是一个简单的工作程序示例,该工作程序按顺序下载某些网站的内容:

class DownloadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
override fun doWork(): ListenableWorker.Result {
for (i in 0..99) {
try {
downloadSynchronously("https://www.google.com")
} catch (e: IOException) {
return ListenableWorker.Result.failure()
}
}
return ListenableWorker.Result.success()
}
}

Note that Worker.doWork() is a synchronous call - you are expected to do the entirety of your background work in a blocking fashion and finish it by the time the method exits. If you call an asynchronous API in doWork() and return a Result, your callback may not operate properly. If you find yourself in this situation, consider using a ListenableWorker (see Threading in ListenableWorker).

请注意Worker.doWork()是一个同步调用-您应该以阻塞的方式完成整个后台工作,并在方法退出时完成它。 如果您在doWork()调用异步API并返回Result ,则您的回调可能无法正常运行。 如果您发现自己处于这种情况,请考虑使用ListenableWorker (请参见ListenableWorker中的线程 )。

When a currently running Worker is stopped for any reason, it receives a call to Worker.onStopped(). Override this method or call Worker.isStopped() to checkpoint your code and free up resources when necessary. WhenWorker in the example above is stopped, it may be in the middle of its loop of downloading items and will continue doing so even though it has been stopped. To optimize this behavior, you can do something like this:

由于任何原因停止当前运行的Worker ,它将收到对Worker.onStopped()的调用。 重写此方法或调用Worker.isStopped()来检查代码并在必要时释放资源。 上例中的Worker停止时,它可能处于下载项循环的中间,即使已停止,它也将继续这样做。 要优化此行为,您可以执行以下操作:

class DownloadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
override fun doWork(): ListenableWorker.Result {
for (i in 0..99) {
if (isStopped) {
break
}
try {
downloadSynchronously("https://www.google.com")
} catch (e: IOException) {
return ListenableWorker.Result.failure()
}
}
return ListenableWorker.Result.success()
}
}

Once a Worker has been stopped, it doesn't matter what you return from Worker.doWork(); the Result will be ignored.

一旦Worker被停止,从Worker.doWork()返回什么都没有关系。 Result将被忽略。

2.2在CoroutineWorker中进行线程化 (2.2 Threading in CoroutineWorker)

For Kotlin users, WorkManager provides first-class support for coroutines. To get started, include work-runtime-ktx in your gradle file. Instead of extending Worke, you should extend, which has a slightly different API. For example, if you wanted to build a simple CoroutineWorker to perform some network operations, you would do the following:

对于Kotlin用户,WorkManager为协程提供了一流的支持。 首先, 在gradle文件中包含work-runtime-ktx 。 除了扩展Worke ,您应该扩展API,API稍有不同。 例如,如果您想构建一个简单的CoroutineWorker来执行某些网络操作,则可以执行以下操作:

class CoroutineDownloadWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
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()
}
}

Note that CoroutineWorker.doWork() is a suspending function. Unlike Worker, this code does not run on the Executor specified in your Configuration. Instead, it defaults to Dispatchers.Default. You can customize this by providing your own CoroutineContext. In the above example, you would probably want to do this work on Dispatchers.IO, as follows:

请注意CoroutineWorker.doWork()是一个挂起函数。 不像Worker ,这段代码不会对运行的Executor在您指定的Configuration 。 而是默认为Dispatchers.Default 。 您可以通过提供自己的CoroutineContext对此进行自定义。 在上面的示例中,您可能希望在Dispatchers.IO上执行以下工作:

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()
}}

CoroutineWorkers handle stoppages automatically by canceling the coroutine and propagating the cancellation signals. You don't need to do anything special to handle work stoppages.

CoroutineWorker通过取消协程并传播取消信号来自动处理停工。 您不需要做任何特殊的事情来处理停工

2.3 RxWorker中的线程 (2.3 Threading in RxWorker)

We provide interoperability between WorkManager and RxJava2. To get started, include work-rxjava2 the dependency in addition to work-runtime in your gradle file. Then, instead of extending Worker, you should extend RxWorker. Finally override the RxWorker.createWork() method to return a Single<Result> indicating the Result of your execution, as follows:

我们提供WorkManager和RxJava2之间的互操作性。 首先,在gradle文件中除了 work-runtime 之外 ,还包括work-rxjava2 依赖项。 然后,应该扩展RxWorker而不是扩展Worker 。 最后,重写RxWorker.createWork()方法以返回Single<Result>指示执行Result ,如下所示:

public class RxDownloadWorker extends RxWorker {
public RxDownloadWorker(Context context, WorkerParameters params) {
super(context, params);
}
@Override
public Single<Result> createWork() {
return Observable.range(0, 100)
.flatMap { download("https://www.google.com") }
.toList()
.map { Result.success() };
}
}

Note that RxWorker.createWork() is called on the main thread, but the return value is subscribed to a background thread by default. You can override RxWorker.getBackgroundScheduler() to change the subscribing thread.

请注意,在主线程上调用RxWorker.createWork() ,但是默认情况下,返回值已预订给后台线程。 您可以重写RxWorker.getBackgroundScheduler()来更改订阅线程。

Stopping an RxWorker will dispose of the Observers properly, so you don't need to handle work stoppages in any special way.

停止RxWorker会正确处理Observer ,因此您无需以任何特殊方式处理停工

2.4在ListenableWorker中进行线程化 (2.4 Threading in ListenableWorker)

In certain situations, you may need to provide a custom threading strategy. For example, you may need to handle a callback-based asynchronous operation. In this case, you cannot simply rely on a Worker because it can't do the work in a blocking fashion. WorkManager supports this use case with ListenableWorker. ListenableWorker is the lowest-level worker API; Worker, CoroutineWorker, and RxWorker all derive from this class. A ListenableWorker only signals when the work should start and stop and leaves the threading entirely up to you. The start work signal is invoked on the main thread, so it is very important that you go to a background thread of your choice manually.

在某些情况下,您可能需要提供自定义线程策略。 例如,您可能需要处理基于回调的异步操作。 在这种情况下,您不能仅仅依赖于Worker因为它无法以阻塞的方式完成工作。 WorkManager通过ListenableWorker支持此用例。 ListenableWorker是最低级别的工作程序API。 WorkerCoroutineWorkerRxWorker都派生自此类。 ListenableWorker仅在工作应开始和停止的时间发出信号,并将线程完全交给您。 启动工作信号是在主线程上调用的,因此手动进入您选择的后台线程非常重要。

The abstract method ListenableWorker.startWork() returns a ListenableFuture of the Result. A ListenableFuture is a lightweight interface: it is a Future that provides functionality for attaching listeners and propagating exceptions. In the startWork method, you are expected to return a ListenableFuture, which you will set with the Result of the operation once it's completed. You can create ListenableFutures one of two ways:

抽象方法ListenableWorker.startWork()返回ResultListenableFutureListenableFuture是一个轻量级的接口:它是一个Future ,它提供了附加侦听器和传播异常的功能。 在startWork方法中,应该返回一个ListenableFuture ,一旦操作完成,就将其与操作的Result一起设置。 您可以使用ListenableFuture两种方法之一创建ListenableFuture

  1. If you use Guava, use ListeningExecutorService.

    如果使用番石榴,请使用ListeningExecutorService

  2. Otherwise, include councurrent-futures in your gradle file and use CallbackToFutureAdapter.

    否则,在gradle文件中包含councurrent-futures并使用CallbackToFutureAdapter

If you wanted to execute some work based on an asynchronous callback, you would do something like this:

如果要基于异步回调执行某些工作,则可以执行以下操作:

public class CallbackWorker extends ListenableWorker {
public CallbackWorker(Context context, WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public ListenableFuture<Result> 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());
}
}
};
for (int i = 0; i < 100; ++i) {
downloadAsynchronously("https://www.google.com", callback);
}
return callback;
});
}
}

What happens if your work is stopped? A ListenableWorker's ListenableFuture is always canceled when the work is expected to stop. Using a CallbackToFutureAdapter, you simply have to add a cancellation listener, as follows:

如果您停止工作会怎样? 当预期工作停止时,总是取消ListenableWorkerListenableFuture 。 使用CallbackToFutureAdapter ,您只需添加取消监听器,如下所示:

public class CallbackWorker extends ListenableWorker {
public CallbackWorker(Context context, WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public ListenableFuture<Result> 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;
});
}
}

You can read more about them here:

您可以在这里阅读有关它们的更多信息:

https://developer.android.com/reference/androidx/work/Worker https://developer.android.com/reference/androidx/work/ListenableWorker

https://developer.android.com/reference/androidx/work/Worker https://developer.android.com/reference/androidx/work/ListenableWorker

https://developer.android.com/topic/libraries/architecture/workmanager/advanced/long-running

https://developer.android.com/topic/libraries/architecture/workmanager/advanced/long-running

Thanks for reading…

谢谢阅读…

翻译自: https://medium.com/@abhiappmobiledeveloper/use-of-workmanager-in-android-app-part-4-81038067e1dd

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值