RxJava學(xué)習(xí)筆記

前言

最近看到各個公司的項目都在用RxJava,意識到必須要學(xué)習(xí)一下這個庫了,所以找到了“扔物線”所發(fā)表的文章<a >“給 Android 開發(fā)者的 RxJava 詳解”</a>,以下是個人在學(xué)習(xí)過程中的一些筆記與摘要,在此分享蔫骂。

RxJava有四個概念

1、Observable---被觀察者
2、Observer---觀察者
3徒役、subscribe---訂閱
4、事件

RxJava中有三個主要回調(diào)

1窖壕、onNext() ----事件忧勿,多個onNext()會組成事件隊列執(zhí)行。
2瞻讽、onCompleted() ----事件隊列完結(jié)鸳吸,當(dāng)沒有新的onNext事件發(fā)出時,就會調(diào)用onCompleted()速勇。
3晌砾、onError() ----事件隊列異常,當(dāng)事件隊列執(zhí)行過程發(fā)生異常就會調(diào)用該方法烦磁,并且不會再執(zhí)行后續(xù)的onNext()事件养匈。

Observer和Subscriber

1、Subscriber是Observer的子類个初,使用方式基本完全一樣乖寒,并且Observer在使用的時候,也會被先轉(zhuǎn)換成為一個Subscriber后執(zhí)行院溺。

2楣嘁、Subscriber和Observer的區(qū)別主要有兩點:

1)onStart():Subscriber所新增的方法,在subscribe訂閱剛開始珍逸,事件發(fā)送之前被調(diào)用逐虚。但是該方法無法指定線程,它會在subscribe發(fā)生的線程被執(zhí)行谆膳。
2)unsubscribe(): 這是 Subscriber 所實現(xiàn)的另一個接口 Subscription 的方法叭爱,用于取消訂閱。在這個方法被調(diào)用后漱病,Subscriber 將不再接收事件买雾。一般在這個方法調(diào)用前把曼,可以使用 isUnsubscribed() 先判斷一下狀態(tài)。 unsubscribe() 這個方法很重要漓穿,因為在 subscribe() 之后嗤军, Observable 會持有 Subscriber 的引用,這個引用如果不能及時被釋放晃危,將有內(nèi)存泄露的風(fēng)險叙赚。所以最好保持一個原則:要在不再使用的時候盡快在合適的地方(例如 onPause() onStop() 等方法中)調(diào)用 unsubscribe() 來解除引用關(guān)系,以避免內(nèi)存泄露的發(fā)生僚饭。

基本代碼示例

private void loadImg() {
    final int resId = R.mipmap.ic_launcher;
    Observable.create(new Observable.OnSubscribe<Drawable>() {
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        @Override
        public void call(Subscriber<? super Drawable> subscriber) {
            Drawable drawable = getTheme().getDrawable(resId);
            subscriber.onNext(drawable);
            subscriber.onCompleted();
        }
    }).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) {
            mImageView.setImageDrawable(drawable);
        }
    });
}


Subscriber<String> subscriber = new Subscriber<String>() {
        @Override
        public void onCompleted() {
            Log.d("MainActivity", "事件隊列結(jié)束");
        }

        @Override
        public void onError(Throwable e) {
            Log.d("MainActivity", "事件隊列出現(xiàn)異常");
        }

        @Override
        public void onNext(String s) {
            Log.d("MainActivity", s);
        }
    };

    Observable observable = Observable.from(new String[]{"休眠開始", "休眠結(jié)束"}).just("新的吧");
    observable.subscribe(subscriber);

線程控制--Scheduler

在不指定線程的情況下震叮, RxJava 遵循的是線程不變的原則,即:在哪個線程調(diào)用 subscribe()鳍鸵,就在哪個線程生產(chǎn)事件苇瓣;在哪個線程生產(chǎn)事件,就在哪個線程消費事件权纤。如果需要切換線程钓简,就需要用到 Scheduler (調(diào)度器)。

一汹想、RxJava內(nèi)置的幾個Scheduler

1、Schedulers.immediate(): 直接在當(dāng)前線程運行撤蚊,相當(dāng)于不指定線程古掏。這是默認(rèn)的 Scheduler。

2侦啸、Schedulers.newThread(): 總是啟用新線程槽唾,并在新線程執(zhí)行操作。

3光涂、Schedulers.io(): I/O 操作(讀寫文件庞萍、讀寫數(shù)據(jù)庫、網(wǎng)絡(luò)信息交互等)所使用的 Scheduler忘闻。行為模式和 newThread() 差不多钝计,區(qū)別在于 io() 的內(nèi)部實現(xiàn)是是用一個無數(shù)量上限的線程池,可以重用空閑的線程齐佳,因此多數(shù)情況下 io() 比 newThread() 更有效率私恬。不要把計算工作放在 io() 中,可以避免創(chuàng)建不必要的線程炼吴。

4本鸣、Schedulers.computation(): 計算所使用的 Scheduler。這個計算指的是 CPU 密集型計算硅蹦,即不會被 I/O 等操作限制性能的操作荣德,例如圖形的計算闷煤。這個 Scheduler 使用的固定的線程池,大小為 CPU 核數(shù)涮瞻。不要把 I/O 操作放在 computation() 中曹傀,否則 I/O 操作的等待時間會浪費 CPU。

5饲宛、另外皆愉, Android 還有一個專用的 AndroidSchedulers.mainThread(),它指定的操作將在 Android 主線程運行艇抠。

二幕庐、使用方式。

有了這幾個 Scheduler 家淤,就可以使用 subscribeOn() 和 observeOn() 兩個方法來對線程進行控制了异剥。 * subscribeOn(): 指定 subscribe() 所發(fā)生的線程,即 Observable.OnSubscribe 被激活時所處的線程絮重≡┦伲或者叫做事件產(chǎn)生的線程。 * observeOn(): 指定 Subscriber 所運行在的線程青伤《搅或者叫做事件消費的線程。

示例代碼如下:

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);
    }
});

變換

1狠角、map():一對一的變換

示例代碼:

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);
    }
});

上面示例代碼可以看到号杠,變換的作用就是在結(jié)果被回調(diào)之前,對輸入的數(shù)據(jù)進行處理丰歌,再輸出到observer姨蟋。
上述代碼我們看到一個Func1,F(xiàn)unc和Action其實很相似立帖,只是Func是帶有返回值的眼溶,同樣的Func也有多個FuncX。
map()所實現(xiàn)的變換只針對一對一的情況晓勇,即一個輸入得到一個結(jié)果堂飞。

2、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);

可以看到宵蕉,上面的代碼將每一個student所包含該的多個課程全部取了出來酝静,這就是一對多的情況,這種情況就可以通過flatMap來實現(xiàn)羡玛。
flatMap所返回的是一個Observable對象别智,但這個Observable并不會直接發(fā)送到Subscriber的回調(diào)中,而是將這個observable所發(fā)送出來的事件匯集稼稿,構(gòu)成一個新的observable薄榛,再由這個新的observable統(tǒng)一的將事件交給Subscriber的回調(diào)讳窟。

doOnSubscribe()

前面提到Subscriber中有一個onStart()方法,這個方法可以做一些初始化的操作敞恋,是在訂閱開始后丽啡,事件發(fā)送前被調(diào)用的。但是它并不能指定線程硬猫,它永遠只會在subscribe的線程中被執(zhí)行补箍。那當(dāng)我們的初始化操作需要指定線程時就需要使用到doOnSubscribe()來做了。
示例代碼:

Observable.create(onSubscribe)
.subscribeOn(Schedulers.io())
.doOnSubscribe(new Action0() {
    @Override
    public void call() {
        progressBar.setVisibility(View.VISIBLE); // 需要在主線程執(zhí)行
    }
})
.subscribeOn(AndroidSchedulers.mainThread()) // 指定主線程
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);

默認(rèn)情況下啸蜜,doOnSubscribe()也將在subscribe所發(fā)生的線程中被執(zhí)行坑雅,但是如果doOnSubscribe()之后有一個subscribeOn()的話,那么它將會在它后面最近的那個subscribeOn()所指定的線程中執(zhí)行衬横。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末裹粤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蜂林,更是在濱河造成了極大的恐慌遥诉,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件噪叙,死亡現(xiàn)場離奇詭異矮锈,居然都是意外死亡,警方通過查閱死者的電腦和手機构眯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門愕难,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人惫霸,你說我怎么就攤上這事〈械埽” “怎么了壹店?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長芝加。 經(jīng)常有香客問我硅卢,道長,這世上最難降的妖魔是什么藏杖? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任将塑,我火速辦了婚禮,結(jié)果婚禮上蝌麸,老公的妹妹穿的比我還像新娘点寥。我一直安慰自己,他們只是感情好来吩,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布敢辩。 她就那樣靜靜地躺著蔽莱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪戚长。 梳的紋絲不亂的頭發(fā)上盗冷,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機與錄音同廉,去河邊找鬼仪糖。 笑死,一個胖子當(dāng)著我的面吹牛迫肖,可吹牛的內(nèi)容都是我干的锅劝。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼咒程,長吁一口氣:“原來是場噩夢啊……” “哼鸠天!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起帐姻,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤稠集,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后饥瓷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剥纷,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年呢铆,在試婚紗的時候發(fā)現(xiàn)自己被綠了晦鞋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡棺克,死狀恐怖悠垛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情娜谊,我是刑警寧澤确买,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站纱皆,受9級特大地震影響湾趾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜派草,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一搀缠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧近迁,春花似錦艺普、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至官份,卻和暖如春缴罗,著一層夾襖步出監(jiān)牢的瞬間助琐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工面氓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留兵钮,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓舌界,卻偏偏與公主長得像掘譬,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子呻拌,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

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