在Rx链中多次切换线程

时间:2017-09-06 08:23:42

标签: android rx-java rx-java2

我们假设我有以下Android案例:

  1. 请求网络上的群组列表
  2. 显示每个组的一些UI元素
  3. 每个组的请求项目
  4. 显示UI元素 每个项目
  5. 我想使用RxJava执行此操作:

    webService.requestGroups()
            .flatMap(group -> {
                view.showGroup(group);
                return webService.requestItems(group);
            })
            .toList()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
    
            .subscribe(items -> view.showItems(items));
    

    正如您所看到的,我有2个视图对象调用,每个调用都必须在主线程上执行。并且2次调用webService,必须在后台线程上执行。

    此代码的问题:第一次调用视图将在后台执行导致Android RuntimeException(只有原始线程可能会触及视图或其他内容)如果我将.observeOn转移到链的开头 - 第二次webService调用将在主线程中执行。

    我怎样才能游泳"在RxJava链中多次通过线程?

2 个答案:

答案 0 :(得分:13)

来自Rx doc for SubscribeOn

  

SubscribeOn运算符指定Observable将开始运行的线程,无论运算符链中的哪个运算符被调用。另一方面,ObserveOn会影响Observable将在该运算符出现的位置下方使用的线程。因此,您可以在Observable运算符链中的不同点多次调用ObserveOn,以便更改某些运算符在哪些线程上运行。

SubscribeOn运算符只能应用一次并设置起始线程。 ObserveOn可用于在流中的任何位置从一个线程转到另一个线程。所以我认为以下应该做你想做的事情:

webService.requestGroups()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .flatMap(group -> {
        view.showGroup(group);
        return webService.requestItems(group)
                         .subscribeOn(Schedulers.io());
    })
    .toList()
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(items -> view.showItems(items));

但在我看来,这太复杂了。我只想订阅第一个observable,然后为每个组启动一个新链,如下所示:

webService.requestGroups()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(group -> { 
        view.showGroup(group);
        webService.requestItems(group)
            .subscribeOn(Schedulers.io()
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(items -> view.showItems(items));
    });

答案 1 :(得分:2)

基于塞缪尔(Samuel)的答案,您可以使用更简单,非嵌套的语法来做到这一点:

webService.requestGroups()
.subscribeOn(Schedulers.io()) // the first operator (requestGroups) on the IO thread
.observeOn(AndroidSchedulers.mainThread()) //everything below on the main thread
.map(group -> {
    view.showGroup(group);
    return group;
})
.observeOn(Schedulers.io()) //everything below on the IO thread
.flatMap(group -> {
    return webService.requestItems(group);
})
.toList()
.observeOn(AndroidSchedulers.mainThread()) //everything below on the main thread
.subscribe(items -> view.showItems(items));

这里有两个经验法则:

  1. subscribeOn指示可观察对象将在哪个线程上开始执行,它在链中的位置无关紧要,并且应该只出现一次。
  2. observeOn告诉所有后续运算符将在哪个线程上执行(直到遇到另一个observeOn为止);它可能在链中出现多次,从而改变了不同代码段的执行线程(如上例所示)。