RxJava2.0——從放棄到入門

前言

終于到了講RxJava這一期,RxJava是筆者個人非常喜歡的一個開源庫,它很好的將鏈式編程風格和異步結合在一起。RxJava其實已經推出很久了,可以說是已經很火了,但是目前仍然還有相當一部分Android開發者沒有使用過,甚至說是想用,卻不知道怎么用,或者不知道自己的項目哪里可以用到,本著讓廣大開發者理解并且上手項目,從放棄到入門,故推出這邊文章。

注:本文所有的具體代碼實現都在文章最后的github鏈接上

學習RxJava2.0之前需不需要學習RxJava1.0

首先,RxJava1.0和RxJava2.0的核心思想都是觀察者模式,只不過RxJava2.0在RxJava1.0的基礎對一些方法進行了優化,方便于開發者更好地理解其編程思想,同時又增加了一部分新的方法解決1.0存在的問題,例如背壓等。所以,如果你學習過RxJava1.0那么很好,你可能已經理解了什么是觀察者模式;如果你沒有學過RxJava1.0,當然也不必著急,因為本文將從最基本的觀察者模式講起,讓你從最基本最簡單的角度入手RxJava。綜上所述,不管你是不是學過RxJava1.0,都不會影響你學習本篇文章。

觀察者模式

在學習RxJava2.0之前,我們必須要弄明白什么是觀察者模式。按照我的慣例,先上一個百度百科的權威介紹


百度百科的觀察者模式介紹

簡單介紹一下,A和B兩個,A是被觀察者,B是觀察者,B對A進行觀察,B并不是需要時刻盯著A,而是A如果發生了變化,會主動通知B,B會對應做一些變化。舉個例子,假設A是連載小說,B是讀者,讀者訂閱了連載小說,當小說出現了新的連載的時候,會推送給讀者。讀者不用時刻盯著小說連載,而小說有了新的連載會主動推送給讀者。這就是觀察者模式。而RxJava正是基于觀察者模式開發的。


觀察者模式.png

RxJava2.0的基本使用

理解好了觀察者模式,我們開始RxJava2.0的學習。首先引入RxJava2.0相關的類庫。
compile 'io.reactivex.rxjava2:rxjava:2.0.1'

compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

正確使用姿勢:

第一步:創建連載小說(被觀察者)

//被觀察者
        Observable novel=Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext("連載1");
                emitter.onNext("連載2");
                emitter.onNext("連載3");
                emitter.onComplete();
            }
        });

Observable中文意思就是被觀察者,通過create方法生成對象,里面放的參數ObservableOnSubscribe<T>,可以理解為一個計劃表,泛型T是要操作對象的類型,重寫subscribe方法,里面寫具體的計劃,本文的例子就是推送連載1、連載2和連載3,在subscribe中的ObservableEmitter<String>對象的Emitter是發射器的意思。ObservableEmitter有三種發射的方法,分別是void onNext(T value)、void onError(Throwable error)、void onComplete(),onNext方法可以無限調用,Observer(觀察者)所有的都能接收到,onError和onComplete是互斥的,Observer(觀察者)只能接收到一個,OnComplete可以重復調用,但是Observer(觀察者)只會接收一次,而onError不可以重復調用,第二次調用就會報異常。

第二步:創建讀者(觀察者)

//觀察者
        Observer<String> reader=new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                mDisposable=d;
                Log.e(TAG,"onSubscribe");
            }

            @Override
            public void onNext(String value) {
                if ("2".equals(value)){
                    mDisposable.dispose();
                    return;
                }
                Log.e(TAG,"onNext:"+value);
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG,"onError="+e.getMessage());
            }

            @Override
            public void onComplete() {
                Log.e(TAG,"onComplete()");
            }
        };

通過new創建接口,并實現其內部的方法,看方法其實就應該差不多知道干嘛的,onNext、onError、onComplete都是跟被觀察者發射的方法一一對應的,這里就相當于接收了。onSubscribe(Disposable d)里面的Disposable對象要說一下,Disposable英文意思是可隨意使用的,這里就相當于讀者和連載小說的訂閱關系,如果讀者不想再訂閱該小說了,可以調用 mDisposable.dispose()取消訂閱,此時連載小說更新的時候就不會再推送給讀者了。

第三步:讀者和連載小說建立訂閱關系

novel.subscribe(reader);//一行代碼搞定

在這里細心的你,可能已經發現了怎么是小說訂閱了讀者,之所以這樣,是因為RxJava主要是想保持自己的鏈式編程,不得不把Observable(被觀察者)放在前面,這里大家可以理解為小說被讀者訂閱了。

這里我們先看一下輸出效果


輸出效果

小結一下:這就是RxJava2.0最最簡單的用法,創建小說,創建讀者,建立訂閱關系,記住這三步,你就能實現一個最簡單的RxJava2.0的用法。

RxJava2.0的異步和鏈式編程

前言里面有提到,RxJava是支持異步的,但是RxJava是如何做到的呢?這里就需要Scheduler。Scheduler,英文名調度器,它是RxJava用來控制線程。當我們沒有設置的時候,RxJava遵循哪個線程產生就在哪個線程消費的原則,也就是說線程不會產生變化,始終在同一個。然后我們一般使用RxJava都是后臺執行,前臺調用,本著這個原則,我們需要調用observeOn(AndroidSchedulers.mainThread()),observeOn是事件回調的線程,AndroidSchedulers.mainThread()一看就知道是主線程,subscribeOn(Schedulers.io()),subscribeOn是事件執行的線程,Schedulers.io()是子線程,這里也可以用Schedulers.newThread(),只不過io線程可以重用空閑的線程,因此多數情況下 io() 比 newThread() 更有效率。前面的代碼根據異步和鏈式編程的原則,我們可以寫成

 Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext("連載1");
                emitter.onNext("連載2");
                emitter.onNext("連載3");
                emitter.onComplete();
            }
        })
                .observeOn(AndroidSchedulers.mainThread())//回調在主線程
                .subscribeOn(Schedulers.io())//執行在io線程
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.e(TAG,"onSubscribe");
                    }

                    @Override
                    public void onNext(String value) {
                        Log.e(TAG,"onNext:"+value);
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG,"onError="+e.getMessage());
                    }

                    @Override
                    public void onComplete() {
                        Log.e(TAG,"onComplete()");
                    }
                });

這里就是RxJava最常用的寫法,異步+鏈式編程,還要再說一下,subscribe的方法重載,subscribe()方法里什么參數也不放是空實現,也就是說連載小說無論出什么連載,讀者都不關心,推送過來了也不讀,如果讀者只關心onNext方法里的內容,可以直接重載subscribe(Consumer<? spuer T> onNext)這個方法,會減少代碼,當然如果是初學者還是建議創建Observer對象。


subscrib的方法重載

應用場景

說了這么多RxJava2.0的用法,你一定要問了到底在什么情況下使用?下面先給大家介紹一下典型的場景。
一、與Retrofit聯用
Retrofit+RxJava的上網模式已經非?;鹆?,如果有不了解的可以看筆者的這篇文章http://www.lxweimin.com/writer#/notebooks/5118090/notes/25405151
二、Rxpermissions等類庫的使用
基于RxJava的開源類庫Rxpermissions、RxBinding以及RxBus在很多項目中已經非常常見,并且被證明了是極其好用的。
三、所有用到異步的地方
因為RxJava就是一個支持異步的鏈式編程,所以所有的用到異步的地方,我們都可以用RxJava來完成,下面給大家舉幾個例子。
定時執行任務

 Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(123);
                sleep(3000);
                emitter.onNext(456);
            }
        }).observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.e(TAG,integer+"");
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {

                    }
                }, new Action() {
                    @Override
                    public void run() throws Exception {

                    }
                });

看完上面的代碼你肯定在想,這么多代碼,干嘛不直接new Handler().postDelayed()。如果你的程序線程里面做的操作很簡單,那么你用new Handler().postDelayed()無所謂,但是如果你的操作很復雜,那么這時候就體現出了RxJava的好處了,借用扔物線大神的一句話就是"隨著程序邏輯變得越來越復雜,RxJava依然能夠保持簡潔"。
下面來說一個復雜的操作,比如我們要依次加載10張圖片(加載圖片是耗時過程),其中第六張我們延時3秒加載,第7張我們復制到sd卡里,第8張我們要上網絡,那么請問你要怎么做,如果用Handler,必然是各種嵌套,各種邏輯復雜得讓你再看一眼都難受,但是如果使用RxJava呢?

Observable.create(new ObservableOnSubscribe<Drawable>() {
            @Override
            public void subscribe(ObservableEmitter<Drawable> emitter) throws Exception {
                for (int i=0;i<drawableRes.length;i++){
                    Drawable drawable=getResources().getDrawable(drawableRes[i]);
                    //第6個圖片延時3秒后架子
                    if (i==5){
                        sleep(3000);
                    }
                    //復制第7張圖片到sd卡
                    if (i==6){
                        Bitmap bitmap=((BitmapDrawable)drawable).getBitmap();
                        saveBitmap(bitmap,"test.png", Bitmap.CompressFormat.PNG);
                    }
                    //上傳到網絡
                    if (i==7){
                        updateIcon(drawable);
                    }
                    emitter.onNext(drawable);
                }
            }
        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Drawable>() {
                    @Override
                    public void accept(Drawable drawable) throws Exception {
                           //回調后在UI界面上展示出來
                    }
                });

沒有任何嵌套,邏輯依然簡潔,這就是RxJava的好處。

總結

RxJava2.0是非常好用的一個異步鏈式庫,遵循觀察者模式。理解觀察者模式可以根據連載小說和讀者的關系,被觀察者是連載小說,觀察者是讀者,讀者訂閱小說,當小說有了新的連載推送給讀者,這就是觀察者模式;創建RxJava最簡單的步驟,一、創建被觀察者對象,二、創建觀者對象,三創建訂閱關系;RxJava2.0的應用場景,只要記得一句話就是所有的異步都可以用RxJava來做就可以了,尤其是復雜的場景,越是復雜的場景越能體現RxJava的好處。關于RxJava的文章,筆者將會繼續推出兩篇,一篇是《RxJava從入門到進階》講的是RxJava的一些進階操作,例如變換、常用操作符和背壓;另一篇是RxJava相關的類庫的介紹和使用,例如文章中提到的RxBinding、RxPerssions等等。如果喜歡筆者,可以關注一波,謝謝!

最后放上我的github地址(本次demo的代碼基本都在文章上了,不下也可以):https://github.com/kaka10xiaobang/RxJavaDemo

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,978評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,960評論 2 373

推薦閱讀更多精彩內容