How to use "if-else" in RX java chain?

niu yi picture niu yi · Apr 13, 2017 · Viewed 19.8k times · Source

I am a newer on RXJava/RXAndroid. I want to implement this case: chose different way based on some condition in RXJava. For example, first, I fetch user info from network and if this is a VIP user, I will go on to fetch more info from network or just show some info in main thread (break the chain.) Here the flow chart: https://i.stack.imgur.com/0hztR.png

I do some search on this and only find "switchIfEmpty" may help. I write the following code:

getUserFromNetwork("userId")
                .flatMap(new Function<User, ObservableSource<User>>() {
                    @Override
                    public ObservableSource<User> apply(User user) throws Exception {
                        if(!user.isVip){
                            //show user info on MainThread!
                            return Observable.empty();
                        }else{
                            return getVipUserFromNetwork("userId");
                        }
                    }
                }).switchIfEmpty(new ObservableSource<User>() {
                    @Override
                    public void subscribe(Observer<? super User> observer) {
                        //show user info in main thread
                        //just break the chain for normal user
                        observer.onComplete();
                    }
                }).doOnNext(new Consumer<User>() {
                    @Override
                    public void accept(User user) throws Exception {
                        //show vip user info in main thread
                    }
                }).subscribe();

Is there more simple way to achieve this?

Thanks!

Answer

yosriz picture yosriz · Apr 13, 2017

flatMap() is a good choice, you can split the stream with it, but at the end the stream merges together (all emissions from each split observable flows to the main stream). In your code, the switchIfEmpty() is redundant as that's exactly what Observable.empty() do (invoke immediately the onCompleted()), and also you need of course observer on, if you want the display to happen on main thread, but anyhow, I think it's not a good practice to handle this in the middle of the stream.

I think that in your case, you can handle (react to) the user emission in single handler, as it's very similar, just check if that's VIP or not and display it accordingly. so it should look something like this:

getUserFromNetwork("userId")
            .flatMap(new Function<User, ObservableSource<User>>() {
                @Override
                public ObservableSource<User> apply(User user) throws Exception {
                    if (!user.isVip) {
                        return Observable.just(user);
                    } else {
                        return getVipUserFromNetwork("userId");
                    }
                }
            })
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(user -> {
                if (user.isVip){
                    //display vip user
                }else{
                    //display regular user
                }
            });

in this approach you have a single stream flow, without 'side effects' in the middle of the stream.

In case you're handling is totally different (which is not this case), then you can split the stream to 2 separated streams and react to each one differently, this can be done by multicast your getUserFromNetwork() Observable, and from this Observable create 2 different Observable, one that will continue for example getVipUserFromNetwork(), and one that don't, and each can have different subscriber logic. (you can read here my answer regarding multicasting)