简体   繁体   English

在仅发送屏幕上使用MVI

[英]Using MVI on Send-only Screen

I'm trying to create a form, send-only view that has a SignaturePad which once the user clicks on the save button, a save intent gets fired and do some background processing. 我正在尝试创建一个带有SignaturePad的表单,仅发送视图,一旦用户单击“保存”按钮,就会触发保存意图并进行一些后台处理。

I have the following: 我有以下几点:

Presenter: 主持人:

@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);
    }

SignatureFragment: 签名片段:

@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();
    }

Lastly my view: 最后我的看法:

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

The problem is, once my frag gets created, the .startWith gets fired, without the user clicking the button. 问题是,一旦创建我的碎片,便会触发.startWith,而无需用户单击按钮。 After that, if the user clicks on the button, the loading state never gets called (.startwith again) but only the success (or error). 之后,如果用户单击按钮,则加载状态将永远不会被调用(.startwith),而只会调用成功(或错误)。 What am I missing here ? 我在这里想念什么?

Thanks again ! 再次感谢 !

Edit: 编辑:

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

Another process is getting a transparent Bitmap, but after adding startWith, my callable never gets called. 另一个过程是获取透明的位图,但是添加startWith之后,我的可调用对象就永远不会被调用。 If I take it out, it works like a charm. 如果我把它拿出来,它就像一个魅力。

This is just a RxJava mistake, not really Mosby related. 这只是RxJava错误,与Mosby无关。

put .startWith(new SignatureViewState.LoadingState()) (and maybe .onErrorReturn(SignatureViewState.ErrorState::new) ) in the observable returned from switchMap() . .startWith(new SignatureViewState.LoadingState()) (以及.onErrorReturn(SignatureViewState.ErrorState::new) )放入从switchMap()返回的可观察switchMap() Like this: 像这样:

 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());

The observable returned from switchMap only start once the user clicks on your button (because switchMap only triggers after intent has been fired). 从switchMap返回的可观察对象仅在用户单击您的按钮后才开始(因为switchMap仅在触发意图后才触发)。

startWith() means "before you do the real work, emit this first". startWith()意思是“在进行实际工作之前,请先发出此信息”。 If you apply startWith() as you did in your original code snipped, obviously it the observable start with loading, but what you really want is "before saving the signature, start with loading state". 如果像在原始代码中一样应用startWith(),显然可以从加载开始,但是您真正想要的是“在保存签名之前,从加载状态开始”。 Therefore startWith() must be part of the "save signature" observable, and not of the "main" observable per se. 因此, startWith()必须是可观察到的“保存签名”的一部分,而不是本身可观察到的“主要”签名的一部分。

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

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