Rxjava基礎(chǔ)篇

上一篇博客介紹了Rxjava簡(jiǎn)單的使用和基本的流程,這次將會(huì)體驗(yàn)到Rxjava真正的威力。

線程控制-Scheduler(調(diào)度器)

Rxjava最大的特點(diǎn)就是異步,所以線程控制肯定是必不可少的。在Rxjava中線程控制是非常簡(jiǎn)單的。
主要的兩個(gè)方法:

subscribeOn 指定OnSubscribe的call具體實(shí)現(xiàn)的線程。
observeOn指定Subscriber的回調(diào)發(fā)生在主線程

下面對(duì)其中的Rxjava中內(nèi)置的幾個(gè)比較常見(jiàn)的Scheduler進(jìn)行簡(jiǎn)單的介紹。

  • Schedulers.immediate(): 直接在當(dāng)前線程運(yùn)行,相當(dāng)于不指定線程。這是默認(rèn)的 Scheduler。
  • Schedulers.newThread(): 總是啟用新線程,并在新線程執(zhí)行操作。
  • Schedulers.io(): I/O 操作(讀寫(xiě)文件、讀寫(xiě)數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)信息交互等)所使用的 Scheduler。行為模式和 newThread() 差不多,區(qū)別在于 io() 的內(nèi)部實(shí)現(xiàn)是是用一個(gè)無(wú)數(shù)量上限的線程池,可以重用空閑的線程,因此多數(shù)情況下 io() 比 newThread() 更有效率。不要把計(jì)算工作放在 io() 中,可以避免創(chuàng)建不必要的線程。
  • Schedulers.computation(): 計(jì)算所使用的 Scheduler。這個(gè)計(jì)算指的是 CPU 密集型計(jì)算,即不會(huì)被 I/O 等操作限制性能的操作,例如圖形的計(jì)算。這個(gè) Scheduler 使用的固定的線程池,大小為 CPU 核數(shù)。不要把 I/O 操作放在 computation() 中,否則 I/O 操作的等待時(shí)間會(huì)浪費(fèi) CPU。
  • 另外, Android 還有一個(gè)專用的 AndroidSchedulers.mainThread(),它指定的操作將在 Android 主線程運(yùn)行。
    下面是一個(gè)簡(jiǎn)單的實(shí)例:模擬加載一張圖片顯示到ImageView上。
  mImage = (ImageView) findViewById(R.id.image);


        Observable.create(new Observable.OnSubscribe<Drawable>() {
            @Override
            public void call(Subscriber<? super Drawable> subscriber) {
                Drawable drawable = getResources().getDrawable(drawableRes);

                try {
                    Thread.sleep(7000);
            //模擬圖片加載的耗時(shí)操作,如果主線程休眠7s,會(huì)觸發(fā)ANR。以此證明此處不是在主線程中執(zhí)行的。
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                subscriber.onNext(drawable);
                subscriber.onCompleted();
            }
        })
                .subscribeOn(Schedulers.io())//指定subscribe發(fā)生在IO線程
                .observeOn(AndroidSchedulers.mainThread())//指定Subscriber的回調(diào)發(fā)生在主線程中
                .subscribe(new Observer<Drawable>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        Toast.makeText(MainActivity.this, "error", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onNext(Drawable drawable) {
                        mImage.setImageDrawable(drawable);
                    }
                });

運(yùn)行之后,發(fā)現(xiàn)等待一段時(shí)間后,圖片就可以正常顯示在ImageView上。到這里,線程的調(diào)度的使用基本上就介紹完畢。下面開(kāi)始介紹Rxjava中的交換。

交換

這里我們先直接通過(guò)例子來(lái)說(shuō)明交換的作用和用法,然后在來(lái)介紹交換的API和具體使用方法。
考慮這樣一種需求,從數(shù)據(jù)庫(kù)中讀取所有的用戶數(shù)據(jù),用R下java實(shí)現(xiàn)如下:eg1

bservable.create(new Observable.OnSubscribe<List<User>>() {
          @Override
          public void call(Subscriber<? super List<User>> subscriber) {
              List<User> userList = null;
              ···
              //從數(shù)據(jù)庫(kù)獲取用戶表數(shù)據(jù)并賦給userList
              ···
              subscriber.onNext(userList);
          }
      }).subscribe(new Action1<List<User>>() {
          @Override
          public void call(List<User> users) {

              //獲取到用戶信息列表
          }
      });

然后,我們實(shí)際上只需要一個(gè)叫"xiaochu"的用戶,然后我們代碼就變成了下面的樣式:eg2

Observable.create(new Observable.OnSubscribe<List<User>>() {
          @Override
          public void call(Subscriber<? super List<User>> subscriber) {
              List<User> userList = null;
              ···
              //從數(shù)據(jù)庫(kù)獲取用戶表數(shù)據(jù)并賦給userList
              ···
              subscriber.onNext(userList);
          }
      }).flatMap(new Func1<List<User>, Observable<User>>() {
          @Override
          public Observable<User> call(List<User> users) {
              return Observable.from(users);
          }
      }).filter(new Func1<User, Boolean>() {
          @Override
          public Boolean call(User user) {
              return user.getName().equals("xiaochu");
          }
      }).subscribe(new Action1<User>() {
          @Override
          public void call(User user) {
              //xiaochu的數(shù)據(jù)
          }
      });

如果這個(gè)時(shí)候,我們需要使用xiaochu爸爸的數(shù)據(jù),那么我們可以這么實(shí)現(xiàn):eg3

Observable.create(new Observable.OnSubscribe<List<User>>() {
          @Override
          public void call(Subscriber<? super List<User>> subscriber) {
              List<User> userList = null;
              ···
              //從數(shù)據(jù)庫(kù)獲取用戶表數(shù)據(jù)并賦給userList
              ···
              subscriber.onNext(userList);
          } 
     }).flatMap(new Func1<List<User>, Observable<User>>() {
          @Override
          public Observable<User> call(List<User> users) {
              return Observable.from(users);
          }
      }).filter(new Func1<User, Boolean>() {
          @Override
          public Boolean call(User user) {
              return user.getName().equals("xiaochu");
          }
      }).map(new Func1<User, User>() {
          @Override
          public User call(User user) { 
              //根據(jù)xiaochu的數(shù)據(jù)user從數(shù)據(jù)庫(kù)查找出xiaochu的父親user2
              return user2;
          }
      }).subscribe(new Action1<User>() {
          @Override
          public void call(User user2) {
            //拿到xiaochu爸爸的數(shù)據(jù)
          }
      });

從上面的示例中,可以看出來(lái)Rxjava強(qiáng)大的可擴(kuò)展性吧。下面我們對(duì)其中的變化來(lái)進(jìn)行具體的分析。

** 1. map() ** 事件對(duì)象的直接變換。
map()的使用在eg3就有具體的體現(xiàn)。
在Map參數(shù)中出現(xiàn)一個(gè)叫做Func1的類,與Action1非常相似,只不過(guò)他有返回值。與Action相似的是,F(xiàn)unc也有多個(gè)(0-9)表示不同的參數(shù)的個(gè)數(shù)。
可以看到,通過(guò)map,我們將xiaochu的數(shù)據(jù)轉(zhuǎn)換呈了xiaochu爸爸的數(shù)據(jù)。

**2. flatMap() ** 事件對(duì)象轉(zhuǎn)換成Observable對(duì)象。
flatMap的使用在eg2就有具體的體現(xiàn)。通過(guò)flatMap,返回一個(gè)Observable對(duì)象,并且這個(gè)Observable對(duì)象并不是直接發(fā)送到了Subscriber的回調(diào)方法中。只是將傳入的事件對(duì)象創(chuàng)建一個(gè)Observable,并將其激活,然后Observable匯入到同一個(gè)observable對(duì)象中,這個(gè)observable負(fù)責(zé)將這些事件統(tǒng)一交給了Subscriber的回調(diào)方法。這樣做的好處就是將事件分成了兩級(jí),更加高效。
在eg2中,通過(guò)flatMap獲取到了所有的users數(shù)據(jù),并將他存儲(chǔ)到Observable中。

**3. filter() ** 對(duì)Observable流程的數(shù)據(jù)進(jìn)行過(guò)濾處理。返回值為false不會(huì)發(fā)送到Subscriber參照eg2的寫(xiě)法。eg2就過(guò)濾只剩下user名字為xiaochu的用戶數(shù)據(jù)。
說(shuō)明:filter的實(shí)現(xiàn)是lift()的變換處理,詳細(xì)請(qǐng)參考lift變換部分。另外,filter()返回了一個(gè)新的Observable,因此若不是采用上面這種直接流方式,而是分步調(diào)用方式,需要將新返回的Observable賦給原來(lái)的Observable。

至于更加復(fù)雜的變化以及原理,這里就不做記錄了。有興趣的可以參考博客。http://gank.io/post/560e15be2dca930e00da1083

別看了,看也沒(méi)有源代碼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容