2016-12-03 114 views
0

我想链接几个可观察对象并根据可观察对象执行什么操作。但我面对奇怪的行为。Android RxJava和可观察链接

class MainActivity : AppCompatActivity() { 

    val TAG: String = MainActivity::class.java.name 

    private lateinit var clicker: TextView 

    override fun onCreate(savedInstanceState: Bundle?) { 
     super.onCreate(savedInstanceState) 
     setContentView(R.layout.activity_main) 
     clicker = findViewById(R.id.clicker) as TextView 
     clicker.setOnClickListener { 
      val i = AtomicInteger() 

      getFirstObservable() 
       .subscribeOn(Schedulers.computation()) 
       .observeOn(AndroidSchedulers.mainThread()) 
       .doOnNext { 
        showMessage(i, it) 
       } 
       .flatMap { getSecondObservable() } 
       .doOnNext { 
        showMessage(i, it) 
       } 
       .flatMap { getThirdObservable() } 
       .doOnNext { 
        showMessage(i, it) 
       } 
       .subscribe() 
     } 
    } 

    fun getFirstObservable(): Observable<String> { 
     return Observable.fromCallable { 
      Thread.sleep(2000) 
      "Hello" 
     } 
    } 

    fun getSecondObservable(): Observable<Int> { 
     return Observable.fromCallable { 
      Thread.sleep(2000) 
      3 
     } 
    } 

    fun getThirdObservable(): Observable<String> { 
     return Observable.fromCallable { 
      Thread.sleep(2000) 
      "World!" 
     } 
    } 

    fun showMessage(i: AtomicInteger, obj: Any) { 
     val msg = "Message #${i.incrementAndGet()}: from ${Thread.currentThread().name}: $obj" 
     Log.e(TAG, msg) 
     clicker.text = msg 
     Toast.makeText(this, msg, Toast.LENGTH_SHORT).show() 
    } 
} 

在这个例子中的日志会显示每2秒,但是当最后一个可观察将完成并享有所有变更都被完成。

12-04 01:11:30.465 19207-19207/com.googlevsky.rxtest E/com.googlevsky.rxtest.MainActivity: Message #1: from main: Hello 
12-04 01:11:32.473 19207-19207/com.googlevsky.rxtest E/com.googlevsky.rxtest.MainActivity: Message #2: from main: 3 
12-04 01:11:34.479 19207-19207/com.googlevsky.rxtest E/com.googlevsky.rxtest.MainActivity: Message #3: from main: World! 

我认为这是)AndroidScheduler.mainThread(的行为,因为当我删除此行,敷,享有变化这样

Handler(Looper.getMainLooper()).post { 
    clicker.text = msg 
    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show() 
} 

行为变得正确。那么有人可以解释这种行为并提出解决这个问题的正确方法吗?

+0

doOnNext/flatMap和其他不在主线程中调用。 observeOn - 为传递给subscribe()方法的param设置调度器。 – Ufkoku

+0

@Ufkoku我添加日志的问题。 doOnNext在主线程上调用 – dewarder

回答

1

大部分代码正在主线程上执行,包括睡眠。当创建observable时,除非另有说明,否则它将订阅并在当前线程上观察。当你创建你的第二和第三个可观察对象时,它们在主线程上。此外,由于没有可观察工作的背景,因此当您订阅时,它会立即在当前线程上执行。因此,所有的工作和观察都发生在主线程上,而不会退回到android操作系统。 UI在主线程上被阻塞等待时间。如果你增加这些睡眠时间,你可以强制ANR。要修复它,您可以为每个可观察对象指定observeOnsubscribeOn,以将工作推送到每个对象的计算线程。

getFirstObservable().subscribeOn(Schedulers.computation()) 
        .observeOn(AndroidSchedulers.mainThread()) 
        .doOnNext { 
         showMessage(i, it) 
        } 
        .flatMap { 
         getSecondObservable().subscribeOn(Schedulers.computation()) 
              .observeOn(AndroidSchedulers.mainThread()) 
        } 
        .doOnNext { 
         showMessage(i, it) 
        } 
        .flatMap { 
         getThirdObservable().subscribeOn(Schedulers.computation()) 
              .observeOn(AndroidSchedulers.mainThread()) 
        } 
        .doOnNext { 
         showMessage(i, it) 
        } 
        .doOnNext { 
         showMessage(i, it) 
        } 
        .subscribe()