在WorkManager组件中,RxJava的同步或异步方式,哪种是正确的选择?

21

我刚接触新的架构组件WorkManager,我使用Retrofit和RxJava进行API调用。

我的使用场景是从后端获取新的帖子,然后显示通知并更新小部件。

因此,Worker类中doWork()方法内的代码可能如下所示。

@NonNull
  @Override
  public Result doWork() {
    AppDependencies appDependencies = new AppDependencies((Application) getApplicationContext());
    Repository repository = appDependencies.getRepository();

    repository.getNewPosts()
        .flatMap(newPosts -> repository.inserPosts(newPosts).toObservable())
        .doOnError(Timber::e)
        //if success - > return  Result.SUCCESS,
        // -> show notification
        // -> update widget
        // error-> return Result.Failure
        .dontKnowWhatBestNextThing; //blocking or subscribing

    //if we reached here then Retry
    return Result.RETRY;
  }

我的问题是如何正确地在Worker类中使用RxJava代码,因为doWork()方法有一个返回值,所以我必须使Rx代码同步吗?

如果我正在使用非阻塞的Rx方法,那么如何返回值(成功-失败-重试)?


在 lambda 内部,我们显然可以返回任何一个状态 - 成功、失败或重试,只需确保相同的行是执行的最后一行。 - Debdeep
@Debdeep,你能否请提供一些代码来更清晰地说明吗? - Mohamed Ibrahim
onErroronSuccess中使用带有大括号的lambda表达式,由于我们知道任一条件都可以工作并且可能是链接中的最后一个条件,在大括号内完成您的工作,并在最后一行将相应状态返回给WorkManager - Debdeep
通常情况下,您希望从内部返回状态。在极少数情况下,可以在结尾处返回Result.RETRY。 - Debdeep
顺便提一下,通过将应用程序上下文强制转换为应用程序的引用并不保证可行。我经常看到它在模拟器中失败,但在真实设备上也很少见。更安全的方法是在应用程序的“onCreate”中设置一个静态字段并提供一个静态getter。 - StackOverthrow
你能和我们分享最后的结果吗?我有点迷失了,需要一些提示。 - Ran
5个回答

38

自从 WorkManager 版本 1.0.0-alpha12 以后,他们添加了一个名为 work-rxjava2 的新组件,其中包含专门用于此目的的 RxWorker 类。它是 ListenableWorker 的特殊情况,期望传入类型为 Single<Result>

要实现它,首先确保在你的 build.gradle 中引入了正确的依赖:

dependencies {
   ...
   implementation "android.arch.work:work-runtime-ktx:$work_version"
   implementation "android.arch.work:work-rxjava2:$work_version"
}

并实现您的 RxWorker

class MyRxWorker(context : Context, params : WorkerParameters) : RxWorker(context, params) {

    val remoteService = RemoteService()

    override fun createWork(): Single<Result> {
        return remoteService.getMySingleResponse()
                .doOnSuccess { /* process result somehow */ }
                .map { Result.success() }
                .onErrorReturn { Result.failure() }
    }
}

远程服务是什么?您能详细解释一下吗?因为我已经被这个问题困扰了几天。 - Edhar Khimich
2
远程服务只是您可能用来返回包装在Single类型中的某些值的示例服务。 - Semanticer

6

编辑: WorkManager现在已经正式支持RxWorker。请查看上面的答案获取更多信息。

doWork发生在后台线程上,因此它是安全的可以阻塞。在返回Result之前,您应该等待Observable完成。

我们还在努力使这个过程更加容易使用异步API,敬请关注。


1
是的,将Rx代码改为同步。doWork的文档很少,但描述

重写此方法以进行实际的后台处理。

意味着预期或至少允许阻塞。当然,在网络请求解决之前,您无法知道doWork应该返回什么。

0

你可以在 Work Manager 中同时使用 Rxjava 和 Coroutine。可以查看这篇Medium文章,希望对你有所帮助。谢谢。


0
我找到了解决方案。 你应该使用RxWorker或SettableFuture进行异步作业。
这是我获取当前位置的解决方案。运作良好。
class LocationWorker(context: Context, private val workerParams: WorkerParameters) :
ListenableWorker(context, workerParams) {

lateinit var mFuture: SettableFuture<ListenableWorker.Result>
private var fusedLocationProviderClient = FusedLocationProviderClient(context)

@SuppressLint("RestrictedApi", "MissingPermission")
override fun startWork(): ListenableFuture<Result> {
    val uniqueId = workerParams.inputData.getString(UNIQUE_ID_KEY)
    mFuture = SettableFuture.create()
    Timber.d("mFutureStart")
    fusedLocationProviderClient.lastLocation.addOnSuccessListener { location ->
        Timber.d("location == $location")
        if (location != null) {
            mFuture.set(Result.success())
        } else mFuture.set(Result.failure())
      }
    return mFuture
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接