Синхронный или асинхронный Rxjava внутри Worker (из компонента WorkManager), какой правильный выбор?
Я новичок в новом компоненте архитектуры WorkManager, я выполняю свои API-вызовы через Retrofit и RxJava.
Моим вариантом использования здесь является получение новых сообщений из Backend, затем просмотр уведомлений и обновление виджета.
Таким образом, код внутри метода doWork() из класса Worker может выглядеть примерно так.
@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;
}
Мой вопрос - это правильный способ использования кода RxJava внутри класса Worker, потому что метод doWork() имеет возвращаемое значение, поэтому мне нужно сделать Rx-код синхронным.
если я использую неблокирующий Rx-подход, как я могу вернуть значение (Success - Failure - Retry)
Ответы
Ответ 1
Начиная с версии WorkManager 1.0.0-alpha12
они добавили новый артефакт под названием work-rxjava2
который включает класс RxWorker
именно для этой цели. Это особый случай ListenableWorker
ожидающего Single<Result>
.
Чтобы реализовать это, сначала убедитесь, что вы включили правильные артефакты в свой build.gradle
:
dependencies {
...
implementation "android.arch.work:work-runtime-ktx:1.0.0-beta01"
implementation "android.arch.work:work-rxjava2:1.0.0-beta01"
}
И RxWorker
свой 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
Изменить: WorkManager теперь официально поддерживает RxWorker
. Посмотрите на ответ выше для получения дополнительной информации.
doWork
происходит в фоновом потоке. Так что это безопасно заблокировать. Вам следует подождать, пока Observable
завершится, прежде чем вернуть Result
.
Мы также работаем над тем, чтобы сделать это проще с помощью асинхронных API. Оставайтесь в курсе.
Ответ 3
Да, сделать код Rx синхронным. Документация для doWork минимальна, но описание
Переопределите этот метод, чтобы выполнить фактическую фоновую обработку.
подразумевает, что он ожидал или, по крайней мере, позволил заблокировать. И, конечно, вы не можете знать, что должен вернуть doWork
пока не будет решен сетевой запрос.
Ответ 4
Я нашел решение. Вы должны использовать 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
}
}