RxJava和Retrofit的結(jié)合(一)

Android RxJava詳解

    這兩天閑來(lái)無(wú)事就想著學(xué)習(xí)一下當(dāng)前比較流行的框架揉燃,看到網(wǎng)上很多大神推薦RxJava
和Retrofit的混合使用,就想著自己也學(xué)習(xí)一下封裝一下植酥,于是就查閱了很多文章總是感
覺(jué)缺少點(diǎn)什么依啰,直到碰到了他的文章(鏈接在文章末尾)才有一種恍然大悟的感覺(jué)乌妙,在此做
一個(gè)總結(jié)袄膏。

響應(yīng)式代碼的基本組成部分是Observables和Subscribers(事實(shí)上Observer才是最小的構(gòu)建塊布轿,但實(shí)踐中使用最多的是Subscriber奠蹬,因?yàn)镾ubscriber才是和Observables的對(duì)應(yīng)的朝聋。)。Observable發(fā)送消息囤躁,而Subscriber則用于消費(fèi)消息冀痕。

  • RxJava 基本概念

    • Observable (可觀察者,即被觀察者)
    • Observer (觀察者)
    • subscribe (訂閱)狸演、事件
    • Scheduler 調(diào)度器言蛇,相當(dāng)于線程控制器

    Observable 和Observer 通過(guò) subscribe() 方法實(shí)現(xiàn)訂閱關(guān)系,從而 Observable 可以在需要的時(shí)候發(fā)出事件來(lái)通知 Observer宵距。

  • RxJava的實(shí)現(xiàn)流程

    • 創(chuàng)建Observer(觀察者)

      Observer 即觀察者,它決定事件觸發(fā)的時(shí)候?qū)⒂性鯓拥男袨?RxJava中的Observer的實(shí)現(xiàn)方式:

        Observer<String> observer = new Observer<String>() {
            @Override
            public void onNext(String s) {
                Log.d(tag, "Item: " + s);
            }
      
            @Override
            public void onCompleted() {
                Log.d(tag, "Completed!");
            }
      
            @Override
            public void onError(Throwable e) {
                Log.d(tag, "Error!");
            }
        };
      

      Subscriber是對(duì)Observe的抽象類腊尚,RxJava對(duì)其實(shí)現(xiàn)了一些擴(kuò)展,但是使用方式基本一致:

        Subscriber<String> subscriber = new Subscriber<String>() {
            @Override
            public void onNext(String s) {
                Log.d(tag, "Item: " + s);
            }
         
            @Override
            public void onCompleted() {
                Log.d(tag, "Completed!");
            }
         
            @Override
            public void onError(Throwable e) {
                Log.d(tag, "Error!");
            }
        };
      

      Observer也總是會(huì)先被轉(zhuǎn)換成一個(gè)Subscriber再使用,不同的是Subscriber中又增加了兩個(gè)方法onStart() 和 UnSubscriber();

    • 創(chuàng)建Observable(被觀察者)

      Observable即被觀察者,它決定什么時(shí)候觸發(fā)事件以及觸發(fā)怎樣的事件满哪。RxJava 使用create()方法來(lái)創(chuàng)建一個(gè)Observable,并為它定義事件觸發(fā)規(guī)則:

        Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                subscriber.onNext("Hello");
                subscriber.onNext("Hi");
                subscriber.onNext("Aloha");
                subscriber.onCompleted();
            }
        });
      

      這里傳入了一個(gè)OnSubscribe對(duì)象作為參數(shù)婿斥。OnSubscribe會(huì)被存儲(chǔ)在返回的 Observable對(duì)象中,它的作用相當(dāng)于一個(gè)計(jì)劃表哨鸭,當(dāng)Observable被訂閱的時(shí)候民宿,OnSubscribe的call()方法會(huì)自動(dòng)被調(diào)用,事件序列就會(huì)依照設(shè)定依次觸發(fā)(對(duì)于上面的代碼像鸡,就是觀察者Subscriber 將會(huì)被調(diào)用三次 onNext() 和一次 onCompleted())活鹰。這樣,由被觀察者調(diào)用了觀察者的回調(diào)方法,就實(shí)現(xiàn)了由被觀察者向觀察者的事件傳遞.

    • 創(chuàng)建Subscribe(訂閱)

      創(chuàng)建了 Observable 和 Observer 之后华望,再用 subscribe() 方法將它們聯(lián)結(jié)起來(lái):

        observable.subscribe(observer);
        // 或者:
        observable.subscribe(subscriber);
      

以上的代碼也可以這么寫(xiě):

Observable.create(new OnSubscribe<Drawable>() {
    @Override
    public void call(Subscriber<? super Drawable> subscriber) {
        Drawable drawable = getTheme().getDrawable(drawableRes));
        subscriber.onNext(drawable);
        subscriber.onCompleted();
    }
    }).subscribe(new Observer<Drawable>() {
        @Override
        public void onNext(Drawable drawable) {
            imageView.setImageDrawable(drawable);
        }

        @Override
        public void onCompleted() {
        }
     
        @Override
        public void onError(Throwable e) {
            Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show();
        }
    });
  • Scheduler--線程控制

    在不指定線程的情況下蕊蝗,RxJava遵循的是線程不變的原則,即:在哪個(gè)線程調(diào)用 subscribe(),就在哪個(gè)線程生產(chǎn)事件赖舟;在哪個(gè)線程生產(chǎn)事件蓬戚,就在哪個(gè)線程消費(fèi)事件。如果需要切換線程宾抓,就需要用到Scheduler(調(diào)度器),下面是Scheduler的API:

    • 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è) Scheduler 嚣艇,就可以使用 subscribeOn() 和 observeOn() 兩個(gè)方法來(lái)對(duì)線程進(jìn)行控制了。

    subscribeOn(): 指定subscribe()所發(fā)生的線程华弓,即 Observable.OnSubscribe被激活時(shí)所處的線程食零。或者叫做事件產(chǎn)生的線程寂屏。

    observeOn(): 指定 Subscriber 所運(yùn)行在的線程贰谣∧嚷В或者叫做事件消費(fèi)的線程。

Demo:

Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 subscribe() 發(fā)生在 IO 線程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調(diào)發(fā)生在主線程
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer number) {
            Log.d(tag, "number:" + number);
        }
    }); 
Operators:RxJava提供了對(duì)事務(wù)序列進(jìn)行變換的功能吱抚,這是RxJava的核心功能之一百宇。變換就是將事件序列中的對(duì)象或整個(gè)序列進(jìn)行加工處理,轉(zhuǎn)換成不同的事件或事件序列秘豹。
  • from操作符可以轉(zhuǎn)換Future携御、Iterable和數(shù)組。對(duì)于Iterable和數(shù)組既绕,產(chǎn)生的Observable會(huì)發(fā)射Iterable或數(shù)組的每一項(xiàng)數(shù)據(jù)啄刹。

      Integer[] items = { 0, 1, 2, 3, 4, 5 };
      Observable myObservable = Observable.from(items);
      
      myObservable.subscribe(
          new Action1<Integer>() {
              @Override
              public void call(Integer item) {
                  System.out.println(item);
              }
          },
          new Action1<Throwable>() {
              @Override
              public void call(Throwable error) {
                  System.out.println("Error encountered: " + error.getMessage());
              }
          },
          new Action0() {
              @Override
              public void call() {
                  System.out.println("Sequence complete");
              }
          }
      );
    
  • Just:Just類似于From,但是From會(huì)將數(shù)組或Iterable的素具取出然后逐個(gè)發(fā)射凄贩,而Just只是簡(jiǎn)單的原樣發(fā)射誓军,將數(shù)組或Iterable當(dāng)做單個(gè)數(shù)據(jù)。

    注意:如果你傳遞null給Just疲扎,它會(huì)返回一個(gè)發(fā)射null值的Observable昵时。不要誤認(rèn)為 它會(huì)返回一個(gè)空Observable(完全不發(fā)射任何數(shù)據(jù)的Observable),如果需要空 Observable你應(yīng)該使用Empty操作符评肆。

      Observable.just(1, 2, 3)
            .subscribe(new Subscriber<Integer>() {
          @Override
          public void onNext(Integer item) {
              System.out.println("Next: " + item);
          }
    
          @Override
          public void onError(Throwable error) {
              System.err.println("Error: " + error.getMessage());
          }
    
          @Override
          public void onCompleted() {
              System.out.println("Sequence complete.");
          }
      });
    
  • map():Map操作符對(duì)原始Observable發(fā)射的每一項(xiàng)數(shù)據(jù)應(yīng)用一個(gè)你選擇的函數(shù)债查,然后返回一個(gè)發(fā)射這些結(jié)果的Observable

      Observable.just("images/logo.png") // 輸入類型 String
      .map(new Func1<String, Bitmap>() {
          @Override
          public Bitmap call(String filePath) { // 參數(shù)類型 String
              return getBitmapFromPath(filePath); // 返回類型 Bitmap
          }
      })
      .subscribe(new Action1<Bitmap>() {
          @Override
          public void call(Bitmap bitmap) { // 參數(shù)類型 Bitmap
              showBitmap(bitmap);
          }
      });
    

map() 方法將參數(shù)中的 String 對(duì)象轉(zhuǎn)換成一個(gè) Bitmap 對(duì)象后返回,而在經(jīng)過(guò) map() 方法后瓜挽,事件的參數(shù)類型也由 String轉(zhuǎn)為了 Bitmap。這種直接變換對(duì)象并返回的征绸,是最常見(jiàn)的也最容易理解的變換久橙。不過(guò) RxJava 的變換遠(yuǎn)不止這樣,它不僅可以針對(duì)事件對(duì)象管怠,還可以針對(duì)整個(gè)事件隊(duì)列淆衷,這使得 RxJava 變得非常靈活。

  • flatMap():

     Student[] students = ...;
     Subscriber<Course> subscriber = new Subscriber<Course>() {
         @Override
         public void onNext(Course course) {
             Log.d(tag, course.getName());
         }
         ...
     };
     Observable.from(students)
         .flatMap(new Func1<Student, Observable<Course>>() {
             @Override
             public Observable<Course> call(Student student) {
                 return Observable.from(student.getCourses());
             }
         })
         .subscribe(subscriber);
    

flatMap() 和 map() 有一個(gè)相同點(diǎn):它也是把傳入的參數(shù)轉(zhuǎn)化之后返回另一個(gè)對(duì)象渤弛。但需要注意祝拯,和 map()不同的是, flatMap() 中返回的是個(gè) Observable 對(duì)象她肯,并且這個(gè) Observable 對(duì)象并不是被直接發(fā)送到了 Subscriber 的回調(diào)方法中佳头。 flatMap() 的原理是這樣的:1. 使用傳入的事件對(duì)象創(chuàng)建一個(gè) Observable 對(duì)象;2. 并不發(fā)送這個(gè) Observable, 而是將它激活晴氨,于是它開(kāi)始發(fā)送事件康嘉;3. 每一個(gè)創(chuàng)建出來(lái)的 Observable 發(fā)送的事件,都被匯入同一個(gè) Observable 籽前,而這個(gè) Observable 負(fù)責(zé)將這些事件統(tǒng)一交給 Subscriber 的回調(diào)方法亭珍。這三個(gè)步驟敷钾,把事件拆成了兩級(jí),通過(guò)一組新創(chuàng)建的 Observable 將初始的對(duì)象『鋪平』之后通過(guò)統(tǒng)一路徑分發(fā)了下去肄梨。而這個(gè)『鋪平』就是 flatMap() 所謂的 flat阻荒。

  • throttleFirst():在每次事件觸發(fā)后的一定時(shí)間間隔內(nèi)丟棄新的事件。常用作去抖動(dòng)過(guò)濾众羡,例如按鈕的點(diǎn)擊監(jiān)聽(tīng)器:

      RxView.clickEvents(button) //RxBinding代碼
      .throttleFirst(500, TimeUnit.MILLISECONDS) //設(shè)置防抖間隔為500ms
      .subscribe(subscriber);
    

建議大家多去理解一下RxJava的變換财松,這是個(gè)難點(diǎn)和功能點(diǎn)邑时。

參考鏈接:泡在網(wǎng)上的日子
大家可以關(guān)注一下驼仪,很多文章寫(xiě)得都不錯(cuò)!這不是打廣告怪得!不是打廣告甜害!打廣告舶掖!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市尔店,隨后出現(xiàn)的幾起案子眨攘,更是在濱河造成了極大的恐慌,老刑警劉巖嚣州,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鲫售,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡该肴,警方通過(guò)查閱死者的電腦和手機(jī)情竹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)匀哄,“玉大人秦效,你說(shuō)我怎么就攤上這事∠呀溃” “怎么了阱州?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)法梯。 經(jīng)常有香客問(wèn)我苔货,道長(zhǎng),這世上最難降的妖魔是什么立哑? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任夜惭,我火速辦了婚禮,結(jié)果婚禮上刁憋,老公的妹妹穿的比我還像新娘滥嘴。我一直安慰自己,他們只是感情好至耻,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布若皱。 她就那樣靜靜地躺著镊叁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪走触。 梳的紋絲不亂的頭發(fā)上晦譬,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音互广,去河邊找鬼敛腌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛惫皱,可吹牛的內(nèi)容都是我干的像樊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼旅敷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼生棍!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起媳谁,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤涂滴,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后晴音,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體柔纵,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年锤躁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了搁料。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡进苍,死狀恐怖加缘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情觉啊,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布沈贝,位于F島的核電站杠人,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏宋下。R本人自食惡果不足惜嗡善,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望学歧。 院中可真熱鬧罩引,春花似錦、人聲如沸枝笨。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至剔桨,卻和暖如春屉更,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背洒缀。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工瑰谜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人树绩。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓萨脑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親饺饭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子渤早,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容