2016-12-03 117 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()