问题
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