在只发送屏幕上使用 MVI

Using MVI on Send-only Screen

我正在尝试创建一个表单,只发送视图,它有一个 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);
}

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

再次感谢!

编辑:

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

另一个进程正在获取透明位图,但是在添加 startWith 之后,我的可调用对象再也没有被调用过。如果我把它拿出来,它就像一个魅力。

这只是一个 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 仅在 intent 被触发后触发)。

startWith()表示"before you do the real work, emit this first"。如果您像在原始代码片段中那样应用 startWith(),显然它是从加载开始的,但您真正想要的是 "before saving the signature, start with loading state"。因此 startWith() 必须是 "save signature" 可观察对象的一部分,而不是 "main" 可观察对象本身的一部分。