sockeqwe / mosby

A Model-View-Presenter / Model-View-Intent library for modern Android apps
http://hannesdorfmann.com/mosby/
Apache License 2.0
5.49k stars 841 forks source link

MVI : How to cancel the login request? #234

Closed CLD1994 closed 7 years ago

CLD1994 commented 7 years ago

image

sockeqwe commented 7 years ago

Please define "cancel". Do you have a cancel button and once the user presses the button you want to cancel the observable from mLogin.buildUseCaseObservable()? Then probably Rx Java's takeUntil() operator is what you are looking for.

http://reactivex.io/documentation/operators/takeuntil.html

CLD1994 commented 7 years ago

Thank you, I try!

CLD1994 commented 7 years ago

This is just the client to ignore the results,Server or have received a message and returns the results。 If it is uploading operation,How do I cancel it?

sockeqwe commented 7 years ago

I'm sorry, I'm not sure what you are aiming to implement, but basically you "stop" an observable if you unsubscribe from it. At least this triggers a signal that the observable should stop doing his work. Then it depends on the implementation whether or not it really stops the work or just "ignores" the onNext calls ("ignore the results"). I think that retrofit stops the http connection on unsubscribe. If you create an observable by your own, you may have to take that into account (and cancel the http request of your underlying http client manually).

Since your question is a purely Rx Java question (and not about mosby) I encourage you to ask that kind of question on http://stackoverflow.com .

Just a mosby related thing to note: If the user leaves your login screen permanently (i.e. clicks on the back button) then the observable chain established via intent(...) and subscribeViewState(...) is unsubscribed and stopped. So if you want that your upload continues even when the user navigates away from your Login screen you better put that upload logic in an Android Service (which has its own lifecycle and lives outside of the Activity / Fragment lifecycle).

Please ask this kind of questions of http://stackoverflow.com . I'm pretty sure there are many people who can answer RxJava related questions quickly.

CLD1994 commented 7 years ago

my english is very poor, expression is not clear. I am using retrofit, unsubscribe can cancel the request.

Disposable disposable = mLogin.buildUseCaseObservable().subscribe();
//stops the http connection on unsubscribe
disposable.dispose();

my intent is as follows

intent(new ViewIntentBinder<LoginView, Boolean>() {
            @NonNull
            @Override
            public Observable<Boolean> bind(@NonNull LoginView view) {
                return view.cancel();
            }
        })
    @Override
    public Observable<Boolean> cancel() {
        return Observable.create(new ObservableOnSubscribe<Boolean>() {
            @Override
            public void subscribe(final ObservableEmitter<Boolean> e) throws Exception {
                mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        dialog.dismiss();
                        if (!e.isDisposed()){
                            e.onNext(true);
                        }
                    }
                });
            }
        });
    }

but use mvi , I can't get requestObservableDisposables.

CLD1994 commented 7 years ago
public class Login extends UseCase<Login.RequestValues, Login.ResponseValue>{

    private DataSource mDataSource;

    @Inject
    public Login(DataSource dataSource) {
        mDataSource = dataSource;
    }

    @Override
    public Observable<ResponseValue> buildUseCaseObservable(RequestValues requestValues) {
        return mDataSource.getRemoteDataSource()
                .getOauthAPI()
                .requestToken(...)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .map(new Function<Oauth, ResponseValue>() {
                    @Override
                    public ResponseValue apply(@NonNull Oauth oauth) throws Exception {
                                            ...
                    }
                })
                .startWith(ResponseValue.newBuilder().withOnLogin(true).build())
                .onErrorReturn(...);
    }

    public static class RequestValues implements UseCase.RequestValues{
               ...
    }

    public static class ResponseValue implements UseCase.ResponseValue{
           ...
    }
}
sockeqwe commented 7 years ago

Something like this should work:

void bindIntents() {
  Observable<?> cancelIntent = intent(LoginView::cancelIntent);

  Observable<LoginViewState> viewState = intent(LoginView::loginIntent)
           .flatMap( 
                     loginRequest -> 
                                      mLogin.buildUseCaseObservable(...)
                                             .takeUntil(cancelIntent)  // TakeUntil directly on buildUserCaseObservable()
           ) // End of flatmap
           .map(...)
           .observeOn(...)
           .onErrorReturn(...);

     subscribeViewState(viewState, LoginView::render);
}
CLD1994 commented 7 years ago

Yes, I do. but There is no disconnect http. There is no way to just lifted loginRequesObservable's subscription And do not damage Observable stream?

intent( (view) -> { return view.login(); } )
        //retrofit: Observable<Oauth> requestToken(...);
        .flatMap( (Function) (loginRequest)  -> { return loginRequesObservable } )

intent( (view) -> { return view.cancel(); } )
sockeqwe commented 7 years ago

Please ask on stackoverflow

陈蓝度 notifications@github.com schrieb am Sa., 8. Apr. 2017, 17:17:

Yes, I do. but There is no disconnect http. There is no way to just lifted loginRequesObservable's subscription And do not damage Observable stream?

intent( (view) -> { return view.login(); } ) //retrofit: Observable requestToken(...); .flatMap( (Function) (loginRequest) -> { return loginRequesObservable } )

intent( (view) -> { return view.cancel(); } )

— You are receiving this because you modified the open/close state.

Reply to this email directly, view it on GitHub https://github.com/sockeqwe/mosby/issues/234#issuecomment-292724394, or mute the thread https://github.com/notifications/unsubscribe-auth/AAjnrnHDiMZ4r_vRLijMGVOvz66eCxJLks5rt6T9gaJpZM4M3rqs .

CLD1994 commented 7 years ago

Thank you very much! I'll according to you recommend to do so

sockeqwe commented 7 years ago

Just ask without mvi / mosby code and I'm sure someone can help you out how to implement such a cancelation properly with RxJava.

陈蓝度 notifications@github.com schrieb am Sa., 8. Apr. 2017, 17:19:

Thank you very much! I'll according to you recommend to do so

— You are receiving this because you modified the open/close state.

Reply to this email directly, view it on GitHub https://github.com/sockeqwe/mosby/issues/234#issuecomment-292724521, or mute the thread https://github.com/notifications/unsubscribe-auth/AAjnrm_i2QS7IS63aeZB2XBqAEhMwKHWks5rt6V0gaJpZM4M3rqs .

CLD1994 commented 7 years ago

Ok, I respect you very much, I will try to learn from you!

sockeqwe commented 7 years ago

Thank you very much for your kind words!

Just wanted to say that the more I think about this problem the more I believe that its very possible that retrofit is not cancelling the http call and just "ignore result" (doesn't deliver result by calling onNext() because the subscriber has unsuscribed caused by takeUntil()). I think it would be a good idea to ask that question on retrofit's github issue tracker.

陈蓝度 notifications@github.com schrieb am Sa., 8. Apr. 2017, 17:25:

Ok, I respect you very much, I will try to learn from you!

— You are receiving this because you modified the open/close state.

Reply to this email directly, view it on GitHub https://github.com/sockeqwe/mosby/issues/234#issuecomment-292724934, or mute the thread https://github.com/notifications/unsubscribe-auth/AAjnro5n5q_rV09_yd15rOvot7JaxeN2ks5rt6b4gaJpZM4M3rqs .

charbgr commented 7 years ago

Seems that retrofit cancels the request.

https://github.com/square/retrofit/blob/master/retrofit-adapters/rxjava2/src/main/java/retrofit2/adapter/rxjava2/CallExecuteObservable.java#L72