如何用 rx-java 替换 'if statement' 以避免回调地狱?
How to replace 'if statement' with rx-java for avoiding callback hell?
我正在尝试用 rx-java 替换我的代码。 (这是非常小的代码。)
已经完成,可以使用了。
但是我想知道...
- 它是一个好的 Rx 样式吗?
- 如果不好,请指出不好的地方
下面是我的 api 处理代码。
之前
Random r = new Random();
boolean apiResult = r.nextBoolean(); // it represents api result. ex. {"result": true} or {"result": false}
if (apiResult == true) {
// do something
System.out.println("result:" + "success");
} else {
// do something
System.out.println("result:" + "failure");
}
之后
Random r = new Random();
Observable<Boolean> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
@Override
public void call(Subscriber<? super Boolean> subscriber) {
// emit true or false
subscriber.onNext(r.nextBoolean());
}
}).cache(1);
// I used filter for split. Is it Rx style?
// success if true emitted.
Observable<Boolean> successStream = apiResultStream
.filter(aBoolean -> aBoolean == true); // here
// failure if false emitted.
Observable<Boolean> failureStream = apiResultStream
.filter(aBoolean -> aBoolean == false); // here
// success flow
successStream
.flatMap(aBoolean -> Observable.just("success"))
// and do something
.subscribe(aString -> System.out.println("result:" + aString));
// failure flow
failureStream
.flatMap(aBoolean -> Observable.just("failure"))
// and do something.
// I want to keep subscriber.
.subscribe(aString -> System.out.println("result:" + aString));
编辑
我差点换了。
(但我有一些非替换代码。它有很多回调和if语句。)
我想避开 'callback hell'.
关键是 'callSuccessApi' 和 'callFailureApi'
之间的结果类型不同
接收前
// callback hell!
callApi(new Callback<Result>(){
@Override
public void success(Result result) {
if (result.Response == true) {
callSuccessApi(new Callback<ResultSuccess>(){
@Override
public void success(ResultSuccess result) {
// and more callbacks...
}
}
} else { // result.Response == false
callFailureApi(new Callback<ResultFailure>(){
@Override
public void success(ResultFailure result) {
// and more callbacks...
}
}
}
}
}
在 rx 之后(避免回调地狱!这是一个好的 Rx 风格吗?)
// change 1st api to observable.(I changed other api to observable)
Observable<Result> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
@Override
public void call(Subscriber<? super Boolean> subscriber) {
callApi(new Callback<Result>(){
@Override
public void success(Result result) {
subscriber.onNext(result);
}
});
}
}).cache(1); // ensure same Observable<Result> for success and failure.
// I used filter for split. Is it Rx style?
// success if result.response == true.
Observable<ResultSuccess> successStream = apiResultStream
.filter(result -> result.response == true); // here
// failure if result.response == false.
Observable<ResultFailure> failureStream = apiResultStream
.filter(result -> result.response == false); // here
// success flow. callSuccessApi return Observable<ResultSuccess>
successStream
.flatMap(result -> callSuccessApi(result))
// and more api call with flatMap...
.subscribe(resultSuccessN -> System.out.println("result:" + resultSuccessN.toString()));
// failure flow. callFailureApi return Observable<ResultFailure>
failureStream
.flatMap(resultFailure -> callFailureApi(result))
// and more api call with flatMap...
.subscribe(resultFailureN -> System.out.println("result:" + resultFailureN.toString()));
抱歉我的英语不好而且问题很长。
更新了我的代码
我在这个问题中得到了 2 个重要信息。(谢谢@Tomáš Dvořák,@Will
- 这是否是一个好方法取决于具体情况。
- 在 map / flatmap / subscribe 中使用 if 语句没有错。
更新代码
Observable<Result> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
@Override
public void call(Subscriber<? super Boolean> subscriber) {
callApi(new Callback<Result>() {
@Override
public void success(Result result) {
subscriber.onNext(result);
}
});
}
});
// In this case, I used 'if' for simply and cleanly.
apiResultStream
.subscribe(result -> {
if (result.response == true) {
callSuccessApi(); // this line looks like 'callback'. but I used this for simply and cleanly.
} else {
callFailureApi();
}
});
有很多方法可以做到这一点,这实际上取决于您的用例。一般来说,我不想分成 2 个流,因为这会使您的代码可读性降低。另外,我不确定您从 flatMap 调用中得到什么好处。在 map 调用中执行 if 东西没有错。
这里有几个选项:
1 - 为了添加日志记录(有点像你的打印行),我使用 doOnEach()
apiResultStream
.doOnEach(next -> {
if (next) logger.info("Logging true " + next);
else logger.info(Logging false " + next);
})
.subscribe(....
2 - 你正在做的工作是你的流的一部分,你以后会想在流上做更多的工作 - 使用 map
apiResultStream
.map(next -> {
if (next) doSomeCallWithNextWhenTrue(next);
else doSomeCallwithNextWhenFalse(next);
})
.subscribe(...
3 - 如果这是你想在管道末端做的工作 - IE 在所有转换或其他类似流的工作完成后,然后在订阅调用中做。
apiResultStream
.subscribe(next -> {
if (next) doSomeCallWithNextWhenTrue(next);
else doSomeCallwithNextWhenFalse(next);
});
问题是 - 对于如此简单的用例,很难提出最佳选择,但我很欣赏在学习 Rx 时,弄清楚如何执行条件语句似乎令人困惑。一般来说,当我调用另一个方法 returns 和 Observable
并在其中执行我的逻辑时,我只使用 map
或 flatMap
。
更新
仍然不确定为什么要拆分流。除非你开始对不同的线程变得聪明,否则第一个订阅调用将阻止第二个订阅调用,这可能不是你想要的。此外,如果您不多次调用 subscribe,则不需要 cache()
调用。
在 map
/ flatmap
/ subscribe
中使用 if statement
没有错。特别是如果它使您的代码更具可读性。
我会做以下事情:
apiResultStream
.flatMap(result -> {
if (result.response == true) {
return callSuccessApi(result)
}
else {
return callFailureApi(result)
})
//Do any more calls you need
.subscribe(...
干净多了。
我对你的 System.out.println
电话订阅有点困惑。这是为了调试或记录目的吗?如果是这样,只需在上面的 if 语句中的 flatMap 中执行此操作。
希望这对您有所帮助,
会
为了避免 if/else 并且不破坏链™,我喜欢使用发布和合并来拆分和重新合并流:
apiResultStream
.publish(results ->
Observable.merge(
results.filter(result -> result.response == true)
.flatmap(result -> callSuccessApiObservable()),
results.filter(result -> result.response == false)
.flatmap(result -> callFailureApiObservable())
)
)
.subscribe(...
我正在尝试用 rx-java 替换我的代码。 (这是非常小的代码。)
已经完成,可以使用了。
但是我想知道...
- 它是一个好的 Rx 样式吗?
- 如果不好,请指出不好的地方
下面是我的 api 处理代码。
之前
Random r = new Random();
boolean apiResult = r.nextBoolean(); // it represents api result. ex. {"result": true} or {"result": false}
if (apiResult == true) {
// do something
System.out.println("result:" + "success");
} else {
// do something
System.out.println("result:" + "failure");
}
之后
Random r = new Random();
Observable<Boolean> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
@Override
public void call(Subscriber<? super Boolean> subscriber) {
// emit true or false
subscriber.onNext(r.nextBoolean());
}
}).cache(1);
// I used filter for split. Is it Rx style?
// success if true emitted.
Observable<Boolean> successStream = apiResultStream
.filter(aBoolean -> aBoolean == true); // here
// failure if false emitted.
Observable<Boolean> failureStream = apiResultStream
.filter(aBoolean -> aBoolean == false); // here
// success flow
successStream
.flatMap(aBoolean -> Observable.just("success"))
// and do something
.subscribe(aString -> System.out.println("result:" + aString));
// failure flow
failureStream
.flatMap(aBoolean -> Observable.just("failure"))
// and do something.
// I want to keep subscriber.
.subscribe(aString -> System.out.println("result:" + aString));
编辑
我差点换了。
(但我有一些非替换代码。它有很多回调和if语句。)
我想避开 'callback hell'.
关键是 'callSuccessApi' 和 'callFailureApi'
之间的结果类型不同接收前
// callback hell!
callApi(new Callback<Result>(){
@Override
public void success(Result result) {
if (result.Response == true) {
callSuccessApi(new Callback<ResultSuccess>(){
@Override
public void success(ResultSuccess result) {
// and more callbacks...
}
}
} else { // result.Response == false
callFailureApi(new Callback<ResultFailure>(){
@Override
public void success(ResultFailure result) {
// and more callbacks...
}
}
}
}
}
在 rx 之后(避免回调地狱!这是一个好的 Rx 风格吗?)
// change 1st api to observable.(I changed other api to observable)
Observable<Result> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
@Override
public void call(Subscriber<? super Boolean> subscriber) {
callApi(new Callback<Result>(){
@Override
public void success(Result result) {
subscriber.onNext(result);
}
});
}
}).cache(1); // ensure same Observable<Result> for success and failure.
// I used filter for split. Is it Rx style?
// success if result.response == true.
Observable<ResultSuccess> successStream = apiResultStream
.filter(result -> result.response == true); // here
// failure if result.response == false.
Observable<ResultFailure> failureStream = apiResultStream
.filter(result -> result.response == false); // here
// success flow. callSuccessApi return Observable<ResultSuccess>
successStream
.flatMap(result -> callSuccessApi(result))
// and more api call with flatMap...
.subscribe(resultSuccessN -> System.out.println("result:" + resultSuccessN.toString()));
// failure flow. callFailureApi return Observable<ResultFailure>
failureStream
.flatMap(resultFailure -> callFailureApi(result))
// and more api call with flatMap...
.subscribe(resultFailureN -> System.out.println("result:" + resultFailureN.toString()));
抱歉我的英语不好而且问题很长。
更新了我的代码
我在这个问题中得到了 2 个重要信息。(谢谢@Tomáš Dvořák,@Will
- 这是否是一个好方法取决于具体情况。
- 在 map / flatmap / subscribe 中使用 if 语句没有错。
更新代码
Observable<Result> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
@Override
public void call(Subscriber<? super Boolean> subscriber) {
callApi(new Callback<Result>() {
@Override
public void success(Result result) {
subscriber.onNext(result);
}
});
}
});
// In this case, I used 'if' for simply and cleanly.
apiResultStream
.subscribe(result -> {
if (result.response == true) {
callSuccessApi(); // this line looks like 'callback'. but I used this for simply and cleanly.
} else {
callFailureApi();
}
});
有很多方法可以做到这一点,这实际上取决于您的用例。一般来说,我不想分成 2 个流,因为这会使您的代码可读性降低。另外,我不确定您从 flatMap 调用中得到什么好处。在 map 调用中执行 if 东西没有错。
这里有几个选项:
1 - 为了添加日志记录(有点像你的打印行),我使用 doOnEach()
apiResultStream
.doOnEach(next -> {
if (next) logger.info("Logging true " + next);
else logger.info(Logging false " + next);
})
.subscribe(....
2 - 你正在做的工作是你的流的一部分,你以后会想在流上做更多的工作 - 使用 map
apiResultStream
.map(next -> {
if (next) doSomeCallWithNextWhenTrue(next);
else doSomeCallwithNextWhenFalse(next);
})
.subscribe(...
3 - 如果这是你想在管道末端做的工作 - IE 在所有转换或其他类似流的工作完成后,然后在订阅调用中做。
apiResultStream
.subscribe(next -> {
if (next) doSomeCallWithNextWhenTrue(next);
else doSomeCallwithNextWhenFalse(next);
});
问题是 - 对于如此简单的用例,很难提出最佳选择,但我很欣赏在学习 Rx 时,弄清楚如何执行条件语句似乎令人困惑。一般来说,当我调用另一个方法 returns 和 Observable
并在其中执行我的逻辑时,我只使用 map
或 flatMap
。
更新
仍然不确定为什么要拆分流。除非你开始对不同的线程变得聪明,否则第一个订阅调用将阻止第二个订阅调用,这可能不是你想要的。此外,如果您不多次调用 subscribe,则不需要 cache()
调用。
在 map
/ flatmap
/ subscribe
中使用 if statement
没有错。特别是如果它使您的代码更具可读性。
我会做以下事情:
apiResultStream
.flatMap(result -> {
if (result.response == true) {
return callSuccessApi(result)
}
else {
return callFailureApi(result)
})
//Do any more calls you need
.subscribe(...
干净多了。
我对你的 System.out.println
电话订阅有点困惑。这是为了调试或记录目的吗?如果是这样,只需在上面的 if 语句中的 flatMap 中执行此操作。
希望这对您有所帮助,
会
为了避免 if/else 并且不破坏链™,我喜欢使用发布和合并来拆分和重新合并流:
apiResultStream
.publish(results ->
Observable.merge(
results.filter(result -> result.response == true)
.flatmap(result -> callSuccessApiObservable()),
results.filter(result -> result.response == false)
.flatmap(result -> callFailureApiObservable())
)
)
.subscribe(...