Android: как обработать результат WorkManager Rx?

Я разрабатываю приложение для Android, используя WorkManager (Android Jetpack) с Rx. Ниже представлен класс Worker.

class ImageRxWorker(
    appContext: Context,
    private val workerParams: WorkerParameters
) : RxWorker(appContext, workerParams) {

    override fun createWork(): Single<Result> = Single.create<Result> { emitter -

        // do the job

        emitter.onSuccess(Result.success())
    }

}

Работает нормально, проблем нет. Но я хочу знать, как я могу справиться с результатом?

class MainPresenter(
    private val view: MainActivity,
    private val workManager: WorkManager = WorkManager.getInstance()
) : MainContract.Presenter {

    override fun startWork(): Completable {
        view.showToastMessage(R.string.worker_started)

        return Completable.create { emitter ->
            val uploadWorkRequest = OneTimeWorkRequestBuilder<ImageRxWorker>().build()
            workManager.enqueue(uploadWorkRequest)
            emitter.onComplete() // This is not exit immediately.
        }
    }

}

Я нашел "addListener", "result", но не знаю, как их использовать. И я попытался погуглить, но не могу найти хорошую ссылку. Кто-нибудь, помогите мне!


Я думаю... Я нашел одно из решений.

Оно работает!!!

Но... это... очень некрасиво... и не умно...

(В моем приложении я не использую LiveData.)

    override fun startWork(): Completable {
        view.showToastMessage(R.string.worker_started)

        return Completable.create { emitter ->
            Log.d(TAG, "[WM][Presenter] startWork - start")
            val workRequest = OneTimeWorkRequestBuilder<ImageRxWorker>()
                .setInputData(workDataOf("TIME" to 1000L))
                .build()

            workManager.enqueue(workRequest)

            while (workManager.getWorkInfoById(workRequest.id).get().state != WorkInfo.State.SUCCEEDED) {
                // Should I really polling?
                Thread.sleep(1000)
                Log.d(TAG, "[WM][Presenter] not yet......")
            }

            Log.d(TAG, "[WM][Presenter] complete")
            emitter.onComplete()
        }
    }

Вау, вот третий код, который был написан ответом «Первого пользователя». Он отлично работает и выглядит лучше, чем второй код. Поскольку мое приложение не использует LiveData, я не могу гарантировать, что этот код действителен.

В «observeForever» я вызываю «cancelWorkById» после завершения работы Worker. Это правильно?

    override fun startWork(): Completable {
        view.showToastMessage(R.string.worker_started)

        return Completable.create { emitter ->
            Log.d(TAG, "[WM][Presenter] startWork - start")
            val workRequest = OneTimeWorkRequestBuilder<ImageRxWorker>()
                .setInputData(workDataOf("TIME" to 1000L))
                .build()

            workManager.enqueue(workRequest)

            workManager.getWorkInfoByIdLiveData(workRequest.id).observeForever { workInfo ->
                workInfo?.outputData?.getString("key")?.let { data ->
                    Log.d(TAG, "[WM][Presenter] startWork - complete: $data")
                    emitter.onComplete()
                    workManager.cancelWorkById(workRequest.id)
                }
            }
        }
    }
1
0
3 838
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Используемый вами метод getWorkInfoById возвращает ListenableFuture, а этот возвращает LiveData :

https://developer.android.com/reference/androidx/work/WorkManager.html#getWorkInfoByIdLiveData(java.util.UUID)

Вместо вашего цикла while вы можете просто наблюдать за рабочим статусом, наблюдая за LiveData, возвращаемым getWorkInfoByIdLiveData(), а затем вызывать emitter.onComplete() после его запуска, но у вас нет LifeCycle здесь, в вашем презентере, поэтому вы должны использовать наблюдатьForever() и позаботьтесь об удалении Наблюдателя,

Вот пример:

workManager.getWorkInfoByIdLiveData(workRequest.id)
 .observeForever(object : Observer<WorkInfo> {
        override fun onChanged(workInfo : WorkInfo?) {
           if (workInfo.state == WorkInfo.State.SUCCEEDED) {
             ////The Work result is a Success
            }
            /* Here We remove the Observer if Not needed anymore
                 'this' here = the Observer */
         workManager.getWorkInfoByIdLiveData(workRequest.id)
          .removeObserver(this) 
        }

Или просто используйте ListenableFuture, возвращаемый getWorkInfoById(), чтобы получить CallBack

Спасибо, я редактирую вопрос с новым кодом, которым вы руководствуетесь. Я не знаю, как я могу «удалить наблюдателя». Поэтому я написал «cancelWorkById» в «observeForever». Не могли бы вы сказать мне, все ли в порядке?

yoonhok 01.04.2019 17:31

Если вы идете по пути LiveData, то сначала объявите Observer, например myObserver, затем вызовите getWorkInfoByIdLiveData().observeForever(myObserver), а затем, когда он сработает, если он вам больше не нужен, вызовите getWorkInfosByIdLiveData.removeObserver(myObserver)

User One 01.04.2019 17:58

И да, использование этих LiveData допустимо, также вызов cancelWorkById() отменит вашу работу, не связанную с LiveData, это не то, что вы хотите, верно? Замените на removeObserver, как я уже сказал, и проверьте параметр данных, когда он срабатывает, возможно, он должен содержать статус (успех и т. д.).

User One 01.04.2019 18:01

Хм... Я понял, но я все еще не знаю, где я могу вызвать "removeObserver". Не могли бы вы дать мне больше руководства, пожалуйста? ...

yoonhok 01.04.2019 18:29

Другие вопросы по теме