java 如何在RX java链中使用“if-else”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43382603/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use "if-else" in RX java chain?
提问by niu yi
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
我是 RXJava/RXAndroid 的新手。我想实现这个案例:根据RXJava中的某些条件选择不同的方式。例如,首先,我从网络获取用户信息,如果这是一个 VIP 用户,我将继续从网络获取更多信息,或者只是在主线程中显示一些信息(中断链)。这里的流程图:https: //i.stack.imgur.com/0hztR.png
I do some search on this and only find "switchIfEmpty" may help. I write the following code:
我对此进行了一些搜索,只发现“switchIfEmpty”可能会有所帮助。我写了以下代码:
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!
谢谢!
回答by yosriz
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.
flatMap()
是一个不错的选择,您可以使用它拆分流,但最终流合并在一起(每个拆分的可观察流的所有排放都流向主流)。在您的代码中, theswitchIfEmpty()
是多余的,因为这正是Observable.empty()
执行的操作(立即调用onCompleted()
),并且您当然还需要观察者,如果您希望显示发生在主线程上,但无论如何,我认为处理这在流的中间。
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:
我认为在您的情况下,您可以在单个处理程序中处理(反应)用户发射,因为它非常相似,只需检查它是否为 VIP 并相应地显示它。所以它应该是这样的:
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 heremy answer regarding multicasting)
如果您处理的是完全不同的(不是这种情况),那么您可以将流拆分为 2 个独立的流并对每个流做出不同的反应,这可以通过多播您的getUserFromNetwork()
Observable来完成,并由此Observable
创建 2 个不同的Observable
,例如getVipUserFromNetwork()
,一种会继续,一种不会,并且每个都可以有不同的订阅者逻辑。(你可以在这里阅读我关于多播的回答)
回答by LookForAngular
I recently found out the switchIfEmptyoperator, which suited my needs and may be useful to some. Rx is still a new way of thinking for me, so I'm also open for suggestions and comments. Let me try to give you another way to think about it. As @yosriz pointed out, using switchIfEmptywith a subsequent onComplete is redundant.
我最近发现了switchIfEmpty运算符,它适合我的需要并且可能对某些人有用。Rx 对我来说仍然是一种新的思维方式,所以我也愿意接受建议和评论。让我试着给你另一种思考方式。正如@yosriz 指出的那样,将switchIfEmpty与后续的 onComplete 一起使用是多余的。
As the name says, switchIfEmptyit switch to another observable when the base one completes without emitting any value.
顾名思义,switchIfEmpty它会在基数完成而不发出任何值时切换到另一个 observable。
These are the 2 cases:
这是2种情况:
- The Observable emits a value and then completes
- The Observable complete without emitting a value.
- Observable 发出一个值然后完成
- Observable 完成而不发出值。
The trick is to use an empty stream as your predicate.
诀窍是使用空流作为谓词。
Given a base observable used as the predicate, if you filter it's emission, you can chain a switchIfEmpty operator to your fallback stream.
给定用作谓词的基本 observable,如果您过滤它的发射,您可以将 switchIfEmpty 运算符链接到您的回退流。
In the following code "User" and "VIP User" share the same interface/class. Even if I'm using Java 8 Lambdas to write the code, notice that there are no IFstatements.
在以下代码中,“用户”和“VIP 用户”共享相同的接口/类。即使我使用 Java 8 Lambdas 编写代码,也要注意没有IF语句。
// User Observable, cached so only 1 network call is done
Observable<User> user = getUserFromNetwork("USER_ID").cache();
// This observable is the user's VIP Status as a boolean stream
Observable<Boolean> isVip = user.map(u -> u.isVip() );
Then we do a bit of logic, we pass downstream the isVip value when he's a VIP, if the user is not a VIP the flatMap will not be evaluated.
然后我们做一点逻辑,当他是VIP时我们向下游传递isVip值,如果用户不是VIP,则不会评估flatMap。
Observable<User> vipUser = isVip
// If VIP emit downstream
.filter(vip -> vip)
// This flatmap is ignored if
// the emission is filtered out ( vip -> vip == false )
.flatMap(vip -> user.flatMap(usr -> {
return getVipUserFromNetwork(usr.getId());
}));
});
At this point the vipUser observable can
此时 vipUser observable 可以
- Emit a value, which is the flatmapped user
- Emit nothing and complete
- 发出一个值,即平面映射用户
- 什么都不发出并完成
When nothing is emitted the switchIfEmpty will call the other observable
当没有发射任何东西时,switchIfEmpty 将调用另一个可观察的
vipUser.switchIfEmpty(user)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(usr -> {
// Logging the class just to understand the outcome
System.out.println("User instanceOf " + usr.getClass());
});
Here's the full code
这是完整的代码
Observable<User> user = getUserFromNetwork("USER_ID").cache();
Observable<Boolean> isVip = user.map(u -> u.isVip() );
Observable<User> vipUser = isVip
.filter(vip -> vip)
.flatMap(vip -> user.flatMap(usr -> {
return getVipUserFromNetwork(usr.getId());
}));
});
vipUser.switchIfEmpty(user)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(usr -> {
// Handle UI Changes
});