Synchronous or Asynchronous Rxjava inside the Worker (from WorkManager component) what's the right choice?

早过忘川 提交于 2019-11-29 02:18:16

问题


I'm new to the new architecture component WorkManager, I do my API calls via Retrofit and RxJava.

My use case here is to get new posts from the Backend, then show notification, and update a widget.

So the code inside doWork() method from the Worker class, may look like something like this.

@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;
  }

My Question is what is the right way to use a RxJava code inside the Worker Class because the doWork() method has a return value, so Do I have to make Rx code Synchronous.

if I'm using the nonblocking Rx approach, how can I return value (Success - Failure - Retry)


回答1:


Since WorkManager version 1.0.0-alpha12 they added a new artifact called work-rxjava2 that includes RxWorker class exactly for this purpose. It is a special case of ListenableWorker expecting Single<Result>.

To implement it, first make sure you include correct artifacts to your build.gradle:

dependencies {
   ...
   implementation "android.arch.work:work-runtime-ktx:1.0.0-beta01"
   implementation "android.arch.work:work-rxjava2:1.0.0-beta01"
}

And implement your 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() }
    }
}



回答2:


Edit: WorkManager now officially supports an RxWorker. Take a look at the answer above for more information.

doWork happens on a background thread. So it's safe to block. You should wait for the Observable to complete before you return a Result.

We are also working on making this easier with asynchronous APIs. Stay tuned.




回答3:


Yes, make the Rx code synchronous. The documentation for doWork is minimal, but the description

Override this method to do your actual background processing.

implies that it's expected or at least allowed to block. And of course, you cannot know what doWork should return until the network request has been resolved.




回答4:


I found the solution. You should use RxWorker or SettableFuture for async job

This is my solution for getting current location. Working like a charm

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


来源:https://stackoverflow.com/questions/51756305/synchronous-or-asynchronous-rxjava-inside-the-worker-from-workmanager-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!