简体   繁体   English

在 RxJava / RxAndroid 中更新有关进度的 UI 时发出单个项目

[英]Emit single item while update UI about progress in RxJava / RxAndroid

I'm currently trying to learn RxJava in Android.我目前正在尝试在 Android 中学习 RxJava。 I require some guides.我需要一些指南。 At the moment, I'm trying to rewrite AsyncTask below to RxJava:目前,我正在尝试将下面的 AsyncTask 重写为 RxJava:

public class MyAsyncTask extends AsyncTask<Void, ProgressInfo, Result> {
    @Override
    protected Result doInBackground(Void... void) {
        //Long running task
        publishProgress(progressInfo);
        //Long running task
        return result;
    }
    @Override
    protected void onProgressUpdate(ProgressInfo... progressInfo) {
        //Update the progress to UI using data from ProgressInfo
    }
    @Override
    protected void onPostExecute(Result res) {
        //Task is completed with a Result
    }
}

In AsyncTask approach shown above, I can update the UI about the progress by making use of onProgressUpdate method, I pack every data I needed into ProgressInfo and reflect the UI in onProgressUpdate .在上面显示的 AsyncTask 方法中,我可以通过使用onProgressUpdate方法更新有关进度的 UI,我将所需的每个数据打包到ProgressInfo中并在onProgressUpdate中反映 UI。 After task ends, the Result will be passed from from doInBackground to onPostExecute .任务结束后, Result将从doInBackground传递到onPostExecute

But, when I'm trying to implement this with RxJava, I have a hard time dealing with it.但是,当我试图用 RxJava 实现它时,我很难处理它。 Since I cannot pass any parameter to onComplete in Observer.由于我无法将任何参数传递给 Observer 中的onComplete And thus, I ended up with following implementation.因此,我最终完成了以下实施。 I merged the pass of the ProgressInfo and Result into onNext .我将ProgressInfoResult的传递合并到onNext中。

 Observable.create(emitter -> {
                //Long running task
                emitter.onNext(progressInfo);
                //Long running task
                emitter.onNext(result);
            }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object -> {
                    if(object instanceof ProgressInfo){
                        //Update the progress to UI using data from ProgressInfo
                    }else if(object instanceof Result){
                        //Task is completed with a Result
                    }
                });

QUESTION 1: Is my implementation/concept in RxJava right or wrong?问题 1:我在 RxJava 中的实现/概念是对还是错?

Although it works, I personally feels the implementation above strange and wrong to me.虽然它有效,但我个人觉得上面的实现对我来说很奇怪和错误。 Since the task ultimately is just trying to do some calculations and come out with a single item - Result .由于任务最终只是尝试进行一些计算并得出一个单一的项目 - Result The emission of ProgressInfo is like a "side" thing but not "main" thing. ProgressInfo的发射就像一个“侧面”的东西,而不是“主要”的东西。 I should implement it with Single.create().我应该用 Single.create() 来实现它。 But if I did this, I cannot think of any way to pass any ProgressInfo to my UI.但是如果我这样做了,我想不出任何方法可以将任何ProgressInfo传递给我的 UI。

QUESTION 2: Is there a better idea/way to emit single item while updating the UI during the process?问题 2:在更新 UI 的过程中,是否有更好的想法/方式来发出单个项目?

If yes, how would you implement this logic in RxJava?如果是,你将如何在 RxJava 中实现这个逻辑? Can you show me your codes/examples?你能告诉我你的代码/例子吗?

QUESTION 1: Is my implementation/concept in RxJava right or wrong?问题 1:我在 RxJava 中的实现/概念是对还是错?

Surely it depends on your use-case.当然,这取决于您的用例。 If you want to provide feedback on each progress-step, there is no way, which I am aware of, to do it differently.如果您想对每个进度步骤提供反馈,据我所知,没有办法以不同的方式进行。 I would recommand to provide progress feedback, when the task takes quite a few time and you are able to provide meaningful progress-information.当任务需要相当长的时间并且您能够提供有意义的进度信息时,我会建议提供进度反馈。

Either use a union of ProgressInfo and Result in one type and test for null or use a marker interface, from which ProgressInfo and Result inherite from.在一种类型中使用 ProgressInfo 和 Result 的并集并测试 null 或使用从 ProgressInfo 和 Result 继承的标记接口。

interface ResultT { }

final class ProgressInfo implements ResultT { }

final class Result implements ResultT { }

When the result is emitted via onNext, I would recommand to complete the observable, in order to give notice to the subscriber, that the task has been done.当结果通过 onNext 发出时,我会建议完成 observable,以便通知订阅者任务已经完成。 The subscriber will receive the result via onNext and a onComplete afterwards.订阅者将通过 onNext 和之后的 onComplete 接收结果。

Observable.<ResultT>create(emitter -> {
        emitter.onNext(progressInfo);
        emitter.onNext(result);

        emitter.onComplete();
    }).subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object -> {
                if (object instanceof ProgressInfo) {
                    //Update the progress to UI using data from ProgressInfo
                } else if (object instanceof Result) {
                    //Task is completed with a Result
                }
            });

If you have no meaningfull progress-information, I would recommend using a Single.如果您没有有意义的进度信息,我建议您使用 Single。

QUESTION 2: Is there a better idea/way to emit single item while updating the UI during the process?问题 2:在更新 UI 的过程中,是否有更好的想法/方式来发出单个项目?

The doOn*-Operators could be used, to update the UI on subscription and termination.可以使用 doOn*-Operators 在订阅和终止时更新 UI。 This way is one of the easiest, but could cause problems, when events from other subscriptions interleave with UI changes^1这种方式是最简单的方式之一,但当来自其他订阅的事件与 UI 更改交错时可能会导致问题^1

.doOnSubscribe(disposable -> {/* update ui */})
            .subscribe(s -> {
                        // success: update ui
                    },
                    throwable -> {
                        // error happened: update ui
                    },
                    () -> {
                        // complete: update ui
                    });

My recommandation would be modelling all States (eg Success/ Error) via a class and switch-case in the the subscribe-method (see ^1).我的建议是通过 class 和订阅方法中的 switch-case 对所有状态(例如成功/错误)进行建模(参见 ^1)。 First emit an StartProgress-event, then the ProgressInformation ones and on finish the SucessResult.首先发出一个 StartProgress 事件,然后是 ProgressInformation 事件,然后完成 SucessResult。 Catch any errors with onError*-operators and return a FailureResult, which contains a error-message and maybe the throwable.使用 onError*-operators 捕获任何错误并返回 FailureResult,其中包含错误消息和可能的 throwable。

Observable.<ResultT>create(emitter -> {
        emitter.onNext(progressInfo);
        emitter.onNext(result);

        emitter.onComplete();
    }).startWith(new StartProgress())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .onErrorReturn(throwable -> new FailureResult(throwable))
            .subscribe(object -> {
                // when StartProgress -> updateUI
                // when ProgressInformation -> updateUI
                // ...
            });

^1 http://hannesdorfmann.com/android/mosby3-mvi-1 ^1 http://hannesdorfmann.com/android/mosby3-mvi-1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM