【问题标题】:Using MVI on Send-only Screen在仅发送屏幕上使用 MVI
【发布时间】:2017-06-20 18:43:05
【问题描述】:

我正在尝试创建一个表单、仅发送视图,该视图具有一个 SignaturePad,一旦用户单击保存按钮,就会触发保存意图并进行一些后台处理。

我有以下几点:

演讲者:

@Override
    protected void bindIntents() {
        Observable<SignatureViewState> observable =
                intent(SignatureView::saveSignature)
                        .switchMap(intent -> Observable.fromCallable(() ->
                                storage.createFile(intent.getFullPath(), intent.getName(), intent.getImage()))
                                .subscribeOn(Schedulers.from(threadExecutor)))
                        .map(SignatureViewState.SuccessState::new)
                        .cast(SignatureViewState.class)
                        .startWith(new SignatureViewState.LoadingState())
                        .onErrorReturn(SignatureViewState.ErrorState::new)
                        .observeOn(postExecutionThread.getScheduler());

        subscribeViewState(observable, SignatureView::render);
    }

签名片段:

@Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        saveButtonClickObservable = RxView.clicks(saveBtn)
                .share()
                .map(bla -> true);

compositeDisposable.add(saveButtonClickObservable.subscribe());

...

@Override
    public Observable<SaveSignatureIntent> saveSignature() {
        Observable<SaveSignatureIntent> saveSignatureIntentObservable =
                Observable.just(new SaveSignatureIntent(savePath, bookingId + ".png", null));

        Observable<SaveSignatureIntent> saveSignatureIntent =
                Observable.zip(signatureBitmapObservable, saveSignatureIntentObservable,
                (signature, intent) -> new SaveSignatureIntent(intent.fullPath, intent.name, signature));

        return saveButtonClickObservable
                .flatMap(bla -> saveSignatureIntent);
    }

    @Override
    public void render(SignatureViewState state) {
        if(state instanceof SignatureViewState.LoadingState)
            renderLoading();
        else if (state instanceof SignatureViewState.SuccessState)
            renderSuccess();

        if(state instanceof SignatureViewState.ErrorState)
            renderError();
    }

最后是我的看法:

public interface SignatureView extends MvpView {
    Observable<SignatureFragment.SaveSignatureIntent> saveSignature();
    void render(SignatureViewState state);
}

问题是,一旦我的 frag 被创建, .startWith 就会被触发,而无需用户单击按钮。 之后,如果用户点击按钮,加载状态永远不会被调用(.startwith 再次),而只会调用成功(或错误)。 我在这里错过了什么?

再次感谢!

编辑:

signatureBitmapObservable = Observable.fromCallable(() -> signaturePad.getTransparentSignatureBitmap(true))
                .subscribeOn(Schedulers.io())
                .startWith(bla -> renderLoading());

另一个进程正在获取透明位图,但在添加 startWith 后,我的可调用对象永远不会被调用。如果我把它拿出来,它就像一个魅力。

【问题讨论】:

    标签: android rx-java2 mosby


    【解决方案1】:

    这只是一个 RxJava 错误,与 Mosby 无关。

    .startWith(new SignatureViewState.LoadingState())(也可能是.onErrorReturn(SignatureViewState.ErrorState::new))放入从switchMap() 返回的可观察对象中。像这样:

     intent(SignatureView::saveSignature)
           .switchMap(intent -> Observable.fromCallable(() ->
                                   storage.createFile(intent.getFullPath(), intent.getName(), intent.getImage()))
                                    .subscribeOn(Schedulers.from(threadExecutor))
                                .map(SignatureViewState.SuccessState::new)
                                .cast(SignatureViewState.class)
                                .startWith(new SignatureViewState.LoadingState())
                                .onErrorReturn(SignatureViewState.ErrorState::new)
           ) // end of switchMap
           .observeOn(postExecutionThread.getScheduler());
    

    从 switchMap 返回的 observable 仅在用户单击您的按钮后启动(因为 switchMap 仅在触发意图后触发)。

    startWith() 的意思是“在你做真正的工作之前,先发出这个”。如果您像在原始代码中所做的那样应用 startWith() ,显然它是可观察的加载开始,但您真正想要的是“在保存签名之前,从加载状态开始”。因此startWith() 必须是“保存签名”可观察对象的一部分,而不是“主要”可观察对象的一部分。

    【讨论】:

    • 谢谢 Hannes,我还在努力学习 Rx。我还有一个忘记提及的问题,我刚刚编辑了我的问题,好吗?
    • 您选择了错误的.startWith() 方法。不要使用.startWith(bla -&gt; renderLoading()); 使用.startWith(object)。这些是相同的方法,但参数完全不同。第一个接受一个 Observable 作为参数(并等待这个传递的 observable 发出一些项目开始,在你的情况下这永远不会发生,因此什么都不会被调用),后一个接受一个具体的对象。使用后一个。在文档中查找差异。
    • 哦,我明白了,但我打算在 startWith 中调用一个方法,以显示加载微调器
    • 不确定您的意思或renderLoading() 的返回值,但可能是.startWith( renderLoading() )
    猜你喜欢
    • 1970-01-01
    • 2021-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-14
    • 2022-10-06
    • 1970-01-01
    相关资源
    最近更新 更多