一、前言
之前我们说 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进行线程的切换