Синхронный или асинхронный 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 внутри рабочего класса, потому что метод doWork () имеет возвращаемое значение, поэтому мне нужно сделать код Rx синхронным.

если я использую неблокирующий подход Rx, как я могу вернуть значение (Успех - Отказ - Повторить)


person Mohamed Ibrahim    schedule 08.08.2018    source источник
comment
Внутри лямбды мы, очевидно, можем вернуть любой из статусов - Успех, Ошибка или Повтор, только убедившись, что эта же строка находится в последней строке выполнения.   -  person Debdeep    schedule 09.08.2018
comment
@Debdeep, не могли бы вы прояснить это с помощью кода   -  person Mohamed Ibrahim    schedule 09.08.2018
comment
используйте лямбда с открытыми фигурными скобками внутри onError или onSuccess, и, поскольку мы знаем, что любое из условий работает и, вероятно, является последним в цепочке, внутри фигурных скобок выполняется ваша работа, а в последней строке вернуть соответствующий статус в WorkManager   -  person Debdeep    schedule 09.08.2018
comment
'return Result.RETRY' в конце - это нормально и должно достигать только в редких случаях. В большинстве случаев вам захочется вернуть статус изнутри.   -  person Debdeep    schedule 09.08.2018
comment
Кстати, получение ссылки на Application путем приведения контекста приложения не гарантируется. В основном я видел, как он терпит неудачу в эмуляторах, но также очень редко на реальных устройствах. Безопаснее установить статическое поле в onCreate приложения и предоставить статический получатель.   -  person StackOverthrow    schedule 09.08.2018
comment
Можете ли вы поделиться с нами последним результатом? Я потерялся и мне нужны подсказки   -  person Ran    schedule 11.10.2018


Ответы (5)


Начиная с версии 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() }
    }
}
person Semanticer    schedule 16.12.2018
comment
Что такое RemoteService? Не могли бы вы объяснить поподробнее? Потому что я зацикливаюсь на этой проблеме на пару дней - person Edgar Khimich; 26.02.2019
comment
удаленная служба - это всего лишь пример службы, которую вы можете использовать для возврата некоторого значения, заключенного в тип Single. - person Semanticer; 01.04.2020

Изменить: WorkManager теперь официально поддерживает RxWorker. Взгляните на ответ выше для получения дополнительной информации.

doWork происходит в фоновом потоке. Так что блокировать безопасно. Вам следует дождаться завершения Observable, прежде чем возвращать Result.

Мы также работаем над тем, чтобы сделать это проще с помощью асинхронных API. Быть в курсе.

person Rahul    schedule 09.08.2018

Да, сделайте код Rx синхронным. Документация для doWork минимальна, но описание

Переопределите этот метод, чтобы выполнить фактическую фоновую обработку.

означает, что это ожидается или, по крайней мере, разрешена блокировка. И, конечно же, вы не можете знать, что doWork должно вернуть, пока сетевой запрос не будет разрешен.

person StackOverthrow    schedule 09.08.2018

Я нашел решение. Вы должны использовать 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
   }
}
person Edgar Khimich    schedule 26.02.2019

Вы можете использовать как Rxjava, так и Coroutine с Work Manager. Взгляните на эту среду сообщение. Надеюсь, это вам поможет. Спасибо.

person Aminul Haque Aome    schedule 18.02.2021