第二章:框架介紹:
1:RxJava介紹:
是實現一個異步操作的庫,類似於異步任務或handler機制。
RxJava 其實就是提供一套異步編程的 API,這套 API 是基於觀察者模式的,而且是鏈式調用的,所以使用 RxJava 編寫的代碼的邏輯會非常簡潔。
RxJava 有以下三個基本的元素:
- 被觀察者(Observable)
- 觀察者(Observer)
- 訂閱(subscribe)
首先在 gradle 文件中添加依賴:
implementation 'io.reactivex.rxjava2:rxjava:2.1.4'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
Demo:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Observable observable = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onNext("a");
emitter.onNext("b");
emitter.onNext("c");
emitter.onComplete();
Log.e("tag", "產生事件");
}
});
Observer observer = new Observer() {
@Override
public void onSubscribe(Disposable d) {
d.dispose();
Log.e("tag", "取消訂閱 ");
}
@Override
public void onNext(Object o) {
Log.e("tag", "接收事件:" + o);
}
@Override
public void onError(Throwable e) {
Log.e("tag", " 數據處理出錯");
}
@Override
public void onComplete() {
Log.e("tag", "數據處理完成");
}
};
observable.map(new Function() {
@Override
public Object apply(Object o) throws Exception {
return o.toString();
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(observer);
}
·被觀察者發送的事件有以下幾種,總結如下表:
總結如下圖:
1. 創建操作符
以下就是講解創建被觀察者的各種操作符。
1.1 create()
方法預覽:
public static <T> Observable<T> create(ObservableOnSubscribe<T> source)
有什麼用:
創建一個被觀察者
Observable observable = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onNext("a");
emitter.onNext("b");
emitter.onNext("c");
emitter.onComplete();
Log.e("tag", "產生事件");
}
});
上面的代碼非常簡單,創建 ObservableOnSubscribe 並重寫其 subscribe 方法,就可以通過 emitter發射器向觀察者發送事件。
然後創建一個觀察者,來驗證這個被觀察者是否成功創建。
Observer observer = new Observer() {
@Override
public void onSubscribe(Disposable d) {
// d.dispose();
Log.e("tag", "取消訂閱 ");
}
@Override
public void onNext(Object o) {
Log.e("tag", "接收事件:" + o);
}
@Override
public void onError(Throwable e) {
Log.e("tag", " 數據處理出錯");
}
@Override
public void onComplete() {
Log.e("tag", "數據處理完成");
}
};
最後用被觀察者訂閱觀察者。
observable.subscribe(observer);
觀察者與被觀察者之間的關係:
觀察者模式面向的需求是:A 對象(觀察者)對 B 對象(被觀察者)的某種變化高度敏感,需要在 B 變化的一瞬間做出反應。舉個例子,新聞裏喜聞樂見的警察抓小偷,警察需要在小偷伸手作案的時候實施抓捕。在這個例子裏,警察是觀察者,小偷是被觀察者,警察需要時刻盯着小偷的一舉一動,才能保證不會漏過任何瞬間。程序的觀察者模式和這種真正的『觀察』略有不同,觀察者不需要時刻盯着被觀察者(例如 A 不需要每過 2ms 就檢查一次 B 的狀態),而是採用註冊(Register)或者稱爲訂閱(Subscribe)的方式,告訴被觀察者:我需要你的某某狀態,你要在它變化的時候通知我。 Android 開發中一個比較典型的例子是點擊監聽器 OnClickListener 。對設置 OnClickListener 來說, View 是被觀察者, OnClickListener 是觀察者,二者通過 setOnClickListener() 方法達成訂閱關係。訂閱之後用戶點擊按鈕的瞬間,Android Framework 就會將點擊事件發送給已經註冊的 OnClickListener 。採取這樣被動的觀察方式,既省去了反覆檢索狀態的資源消耗,也能夠得到最高的反饋速度。當然,這也得益於我們可以隨意定製自己程序中的觀察者和被觀察者,而警察叔叔明顯無法要求小偷『你在作案的時候務必通知我』。
1.2 just()
方法預覽:
public static <T> Observable<T> just(T item)
......
public static <T> Observable<T> just(T item1, T item2, T item3, T item4, T item5, T item6, T item7, T item8, T item9, T item10)複製代碼
有什麼用?
創建一個被觀察者,併發送事件,發送的事件不可以超過10個以上。
Observable.just(1, 2, 3)
.subscribe(new Observer < Integer > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "=================onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "=================onNext " + integer);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "=================onError ");
}
@Override
public void onComplete() {
Log.d(TAG, "=================onComplete ");
}
});
1.3 From 操作符
1.3.1 fromArray()
方法預覽:
public static <T> Observable<T> fromArray(T... items)複製代碼
有什麼用?
這個方法和 just() 類似,只不過 fromArray 可以傳入多於10個的變量,並且可以傳入一個數組。
怎麼用?
Integer array[] = {1, 2, 3, 4};
Observable.fromArray(array)
.subscribe(new Observer < Integer > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "=================onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "=================onNext " + integer);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "=================onError ");
}
@Override
public void onComplete() {
Log.d(TAG, "=================onComplete ");
}
});
1.3.2 fromCallable()
方法預覽:
public static <T> Observable<T> fromCallable(Callable<? extends T> supplier)複製代碼
有什麼用?
這裏的 Callable 是 java.util.concurrent 中的 Callable,Callable 和 Runnable 的用法基本一致,只是它會返回一個結果值,這個結果值就是發給觀察者的。
怎麼用?
Observable.fromCallable(new Callable < Integer > () {
@Override
public Integer call() throws Exception {
return 1;
}
})
.subscribe(new Consumer < Integer > () {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, "================accept " + integer);
}
});
1.3.3 fromFuture()
方法預覽:
public static <T> Observable<T> fromFuture(Future<? extends T> future)複製代碼
有什麼用?
參數中的 Future 是 java.util.concurrent 中的 Future,Future 的作用是增加了 cancel() 等方法操作 Callable,它可以通過 get() 方法來獲取 Callable 返回的值。
怎麼用?
FutureTask < String > futureTask = new FutureTask < > (new Callable < String > () {
@Override
public String call() throws Exception {
Log.d(TAG, "CallableDemo is Running");
return "返回結果";
}
});
Observable.fromFuture(futureTask)
.doOnSubscribe(new Consumer < Disposable > () {
@Override
public void accept(Disposable disposable) throws Exception {
futureTask.run();
}
})
.subscribe(new Consumer < String > () {
@Override
public void accept(String s) throws Exception {
Log.d(TAG, "================accept " + s);
}
});
1.3.4 fromIterable()
方法預覽:
public static <T> Observable<T> fromIterable(Iterable<? extends T> source)複製代碼
有什麼用?
直接發送一個 List 集合數據給觀察者
怎麼用?
List<Integer> list = new ArrayList<>();
list.add(0);
list.add(1);
list.add(2);
list.add(3);
Observable.fromIterable(list)
.subscribe(new Observer < Integer > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "=================onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "=================onNext " + integer);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "=================onError ");
}
@Override
public void onComplete() {
Log.d(TAG, "=================onComplete ");
}
});
1.4 defer()
方法預覽:
public static <T> Observable<T> defer(Callable<? extends ObservableSource<? extends T>> supplier)複製代碼
有什麼用?
這個方法的作用就是直到被觀察者被訂閱後纔會創建被觀察者。
怎麼用?
// i 要定義爲成員變量
Integer i = 100;
Observable<Integer> observable = Observable.defer(new Callable<ObservableSource<? extends Integer>>() {
@Override
public ObservableSource<? extends Integer> call() throws Exception {
return Observable.just(i);
}
});
i = 200;
Observer observer = new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "================onNext " + integer);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
};
observable.subscribe(observer);
i = 300;
observable.subscribe(observer);
運行結果:
05-20 20:05:01.443 26622-26622/? D/chan: ================onNext 200
================onNext 300
因爲 defer() 只有觀察者訂閱的時候纔會創建新的被觀察者,所以每訂閱一次就會打印一次,並且都是打印 i 最新的值
1.5 timer()
方法預覽:
public static Observable<Long> timer(long delay, TimeUnit unit)
......複製代碼
有什麼用?
當到指定時間後就會發送一個 0L 的值給觀察者。
怎麼用?
Observable.timer(2, TimeUnit.SECONDS)
.subscribe(new Observer < Long > () {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Long aLong) {
Log.d(TAG, "===============onNext " + aLong);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
打印結果:
05-20 20:27:48.004 27204-27259/com.example.louder.rxjavademo D/chan: ===============onNext 0
1.6 interval()
方法預覽:
public static Observable<Long> interval(long period, TimeUnit unit)
public static Observable<Long> interval(long initialDelay, long period, TimeUnit unit)
......複製代碼
有什麼用?
每隔一段時間就會發送一個事件,這個事件是從0開始,不斷增1的數字。
怎麼用?
Observable.interval(4, TimeUnit.SECONDS)
.subscribe(new Observer < Long > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "==============onSubscribe ");
}
@Override
public void onNext(Long aLong) {
Log.d(TAG, "==============onNext " + aLong);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
從時間就可以看出每隔4秒就會發出一次數字遞增1的事件。這裏說下 interval() 第三個方法的 initialDelay 參數,這個參數的意思就是 onSubscribe 回調之後,再次回調 onNext 的間隔時間。
1.7 intervalRange()
方法預覽:
public static Observable<Long> intervalRange(long start, long count, long initialDelay, long period, TimeUnit unit)
public static Observable<Long> intervalRange(long start, long count, long initialDelay, long period, TimeUnit unit, Scheduler scheduler)複製代碼
有什麼用?
可以指定發送事件的開始值和數量,其他與 interval() 的功能一樣。
怎麼用?
Observable.intervalRange(2, 5, 2, 1, TimeUnit.SECONDS)
.subscribe(new Observer < Long > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "==============onSubscribe ");
}
@Override
public void onNext(Long aLong) {
Log.d(TAG, "==============onNext " + aLong);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
打印結果:
05-21 00:03:01.672 2504-2504/com.example.louder.rxjavademo D/chan: ==============onSubscribe
05-21 00:03:03.674 2504-2537/com.example.louder.rxjavademo D/chan: ==============onNext 2
05-21 00:03:04.674 2504-2537/com.example.louder.rxjavademo D/chan: ==============onNext 3
05-21 00:03:05.674 2504-2537/com.example.louder.rxjavademo D/chan: ==============onNext 4
05-21 00:03:06.673 2504-2537/com.example.louder.rxjavademo D/chan: ==============onNext 5
05-21 00:03:07.674 2504-2537/com.example.louder.rxjavademo D/chan: ==============onNext 6
可以看出被觀察者的事件產生,從2開始,總共發送5次,onSubscribe 回調
與onNext回調間隔時間爲2秒,事件1秒發送一次。
1.8 range()
方法預覽:
public static Observable<Integer> range(final int start, final int count)複製代碼
有什麼用?
同時發送一定範圍的事件序列。
怎麼用?
Observable.range(2, 5)
.subscribe(new Observer < Integer > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "==============onSubscribe ");
}
@Override
public void onNext(Integer aLong) {
Log.d(TAG, "==============onNext " + aLong);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
打印結果:
05-21 00:09:17.202 2921-2921/? D/chan: ==============onSubscribe
==============onNext 2
==============onNext 3
==============onNext 4
==============onNext 5
==============onNext 6
1.9 rangeLong()
方法預覽:
public static Observable<Long> rangeLong(long start, long count)複製代碼
有什麼用?
作用與 range() 一樣,只是數據類型爲 Long
1.10 empty() & never() & error()
方法預覽:
public static <T> Observable<T> empty()
public static <T> Observable<T> never()
public static <T> Observable<T> error(final Throwable exception)複製代碼
有什麼用?
- empty() : 直接發送 onComplete() 事件
- never():不發送任何事件
- error():發送 onError() 事件
怎麼用?
Observable.empty()
.subscribe(new Observer < Object > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "==================onSubscribe");
}
@Override
public void onNext(Object o) {
Log.d(TAG, "==================onNext");
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "==================onError " + e);
}
@Override
public void onComplete() {
Log.d(TAG, "==================onComplete");
}
});
打印結果:
05-26 14:06:11.881 15798-15798/com.example.rxjavademo D/chan: ==================onSubscribe
==================onComplete
換成 never() 的打印結果:
05-26 14:12:17.554 16805-16805/com.example.rxjavademo D/chan: ==================onSubscribe
換成 error() 的打印結果:
05-26 14:12:58.483 17817-17817/com.example.rxjavademo D/chan: ==================onSubscribe
==================onError java.lang.NullPointerException
2. 轉換操作符
2.1 map()
方法預覽:
public final <R> Observable<R> map(Function<? super T, ? extends R> mapper)複製代碼
有什麼用?
map 可以將被觀察者發送的數據類型轉變成其他的類型
怎麼用?
以下代碼將 Integer 類型的數據轉換成 String。
Observable.just(1, 2, 3)
.map(new Function < Integer, String > () {
@Override
public String apply(Integer integer) throws Exception {
return "I'm " + integer;
}
})
.subscribe(new Observer < String > () {
@Override
public void onSubscribe(Disposable d) {
Log.e(TAG, "===================onSubscribe");
}
@Override
public void onNext(String s) {
Log.e(TAG, "===================onNext " + s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
打印結果:
05-21 09:16:03.490 5700-5700/com.example.rxjavademo E/chan: ===================onSubscribe
===================onNext I'm 1
===================onNext I'm 2
===================onNext I'm 3
2.2 flatMap()
方法預覽:
public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper)
......
有什麼用?
這個方法可以將事件序列中的元素進行整合加工,返回一個新的被觀察者。
怎麼用?
flatMap() 其實與 map() 類似,但是 flatMap() 返回的是一個 Observerable。現在用一個例子來說明 flatMap() 的用法。
假設一個有一個 Person 類,這個類的定義如下:
public class Person {
private String name;
private List<Plan> planList = new ArrayList<>();
public Person(String name, List<Plan> planList) {
this.name = name;
this.planList = planList;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Plan> getPlanList() {
return planList;
}
public void setPlanList(List<Plan> planList) {
this.planList = planList;
}
}
Person 類有一個 name 和 planList 兩個變量,分別代表的是人名和計劃清單。
Plan 類的定義如下:
public class Plan {
private String time;
private String content;
private List<String> actionList = new ArrayList<>();
public Plan(String time, String content) {
this.time = time;
this.content = content;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public List<String> getActionList() {
return actionList;
}
public void setActionList(List<String> actionList) {
this.actionList = actionList;
}
}
現在有一個需求就是要將 Person 集合中的每個元素中的 Plan 的 action 打印出來。 首先用 map() 來實現這個需求看看:
Observable.fromIterable(personList)
.map(new Function < Person, List < Plan >> () {
@Override
public List < Plan > apply(Person person) throws Exception {
return person.getPlanList();
}
})
.subscribe(new Observer < List < Plan >> () {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(List < Plan > plans) {
for (Plan plan: plans) {
List < String > planActionList = plan.getActionList();
for (String action: planActionList) {
Log.d(TAG, "==================action " + action);
}
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
可以看到 onNext() 用了嵌套 for 循環來實現,如果代碼邏輯複雜起來的話,可能需要多重循環纔可以實現。
現在看下使用 flatMap() 實現:
Observable.fromIterable(personList)
.flatMap(new Function < Person, ObservableSource < Plan >> () {
@Override
public ObservableSource < Plan > apply(Person person) {
return Observable.fromIterable(person.getPlanList());
}
})
.flatMap(new Function < Plan, ObservableSource < String >> () {
@Override
public ObservableSource < String > apply(Plan plan) throws Exception {
return Observable.fromIterable(plan.getActionList());
}
})
.subscribe(new Observer < String > () {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
Log.d(TAG, "==================action: " + s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
從代碼可以看出,只需要兩個 flatMap() 就可以完成需求,並且代碼邏輯非常清晰。
2.3 concatMap()
方法預覽:
public final <R> Observable<R> concatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper)
public final <R> Observable<R> concatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper, int prefetch)複製代碼
有什麼用?
concatMap() 和 flatMap() 基本上是一樣的,只不過 concatMap() 轉發出來的事件是有序的,而 flatMap() 是無序的。
更多詳情請看: