一、前言
之前我們說 RxJava是基於起點到終點,之間通過一條線連接,這條線裏我們可以做相應的攔截操作的這種編程思維。其實在規範的稱呼中RxJava是基於觀察者設計模式的一種響應式編程思維。從RxJava兩個關鍵對象就可以看到Observable是我們的被觀察者、Observer是我們的觀察者。Observer通過觀察Observable的數據變換做出響應,然而又說RxJava使用的不是標準的觀察者設計模式。
二、觀察者設計模式
什麼是觀察者設計模式?
如下圖,我們有一個微信公衆號,公衆號可以定時更新文章並推送給關注的用戶。A和B用戶關注了公衆號,當公衆號更新文章的時候A和B收到了相應的推送。在這裏我們的公衆號就是一個被觀察者,A和B用戶就是觀察者。當公衆號更新消息推送的時候,A和B就可以通過觀察收到消息。
- 通過代碼實現
(1)創建被觀察者
package com.example.andoiddemo;
/**
* 被觀察者接口
*/
public interface Observable {
void addUser(Observer user);
void removeUser(Observer user);
void pushMessage(String msg);
}
package com.example.andoiddemo;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public class WeChatObservable implements Observable {
private static final String TAG ="WeChatObservable" ;
private List<Observer> list = new ArrayList<>();
@Override
public void addUser(Observer user) {
list.add(user);
}
@Override
public void removeUser(Observer user) {
list.remove(user);
}
@Override
public void pushMessage(String msg) {
Log.e(TAG, "觀察者推送了一條消息: "+msg );
for (int i = 0; i <list.size() ; i++) {
list.get(i).receiveMessage(msg);
}
}
}
(2)創建觀察者A和B
package com.example.andoiddemo;
/**
* 觀察者
*/
public interface Observer {
/**
* 收到消息
* @param msg
*/
void receiveMessage(String msg);
}
package com.example.andoiddemo;
import android.util.Log;
public class AUserObserver implements Observer {
private static final String TAG = "AUserObserver";
@Override
public void receiveMessage(String msg) {
Log.e(TAG, "A用戶收到了消息: "+msg );
}
}
package com.example.andoiddemo;
import android.util.Log;
public class BUserObserver implements Observer {
private static final String TAG = "BUserObserver";
@Override
public void receiveMessage(String msg) {
Log.e(TAG, "B用戶收到了消息: "+msg );
}
}
(3)測試
private void test7() {
com.example.andoiddemo.Observer a = new com.example.andoiddemo.AUserObserver();
com.example.andoiddemo.Observer b = new com.example.andoiddemo.BUserObserver();
com.example.andoiddemo.Observable observable = new WeChatObservable();
//添加關注
observable.addUser(a);
observable.addUser(b);
observable.pushMessage("hello world");
//移除關注
observable.removeUser(b);
observable.pushMessage("你好世界");
}
2021-06-08 18:00:39.229 25088-25088/com.example.andoiddemo E/WeChatObservable: 觀察者推送了一條消息: hello world
2021-06-08 18:00:39.229 25088-25088/com.example.andoiddemo E/AUserObserver: A用戶收到了消息: hello world
2021-06-08 18:00:39.229 25088-25088/com.example.andoiddemo E/BUserObserver: B用戶收到了消息: hello world
2021-06-08 18:00:39.229 25088-25088/com.example.andoiddemo E/WeChatObservable: 觀察者推送了一條消息: 你好世界
2021-06-08 18:00:39.229 25088-25088/com.example.andoiddemo E/AUserObserver: A用戶收到了消息: 你好世界
通過以上的代碼我們發現,觀察者設計模式的核心就是被觀察者對象中有一個容器,這個容器包含了觀察者對象。當觀察者數據更新的時候,再通過容器中拿到被觀察者對象然後通知他們,這樣一來觀察者就收到了數據更新。再標準的觀察者設計模式中,這裏被觀察者只有一個,觀察者可以有多個。
三、觀察者設計模式與RxJava對比
以上我們知道在標準的觀察者設計模式中,被觀察者只有一個,而觀察者可以有多個。而我們再來看看RxJava的代碼。
private void test8() {
Observable.just("hello world").map(new Function<String, String>() {
@Override
public String apply(@NonNull String s) throws Exception {
return s;
}
}).map(new Function<String, String>() {
@Override
public String apply(@NonNull String s) throws Exception {
return s;
}
}).map(new Function<String, String>() {
@Override
public String apply(@NonNull String s) throws Exception {
return s;
}
}).subscribe(new Observer<String>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull String s) {
Log.e(TAG, "onNext: "+s );
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
}
在test8的方法中我們看到Observable被觀察者通過just輸入一個事件,然後調用了3次map,每一次map操作都返回一個被觀察者,這樣就將事件依次變換傳遞給下面的被觀察者。而我們的觀察者要接收事件做出響應,必須要通過subscribe進行訂閱,並且觀察者響應的是最後一個被觀察者的事件。這裏就和標準的觀察者模式有所區別。
- 標準的觀察者模式,被觀察者只有一個,觀察者可以有多個,當被觀察者發出事件的時候,所有添加的觀察者都能收到事件。
- RxJava中的觀察者設計模式,被觀察者可以有多個,觀察者只有一個,兩者之間通過訂閱進行關聯。並且觀察者只接受最後一個被觀察者的事件。
四、RxJava事件發射以及map事件變換原理
1、事件發射
2、map事件變換
五、線程切換原理
1、subscribeOn(Schedulers.io())
講當前運行環境切換到Io線程,其實就子線程。原理就是將我們observer封裝成runnable對象,由線程池執行。
2、observeOn(AndroidSchedulers.mainThread())
將下面的代碼切換到主線程。原理就是ObservableObserveOn調用subscribe的時候本來應該是調用onNext 講事件往下發射,但是它是先通過Handler進行線程的切換