观察者模式简单介绍
观察者模式又被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。这种模式应用广泛,例如在Android中:
1.Android系统内容提供者 ,内容观察者就采用了这种观察者模式。
2.RecyClerView和ListView的 Adapter就采用了观察者模式。
3. 当两个界面想同时观察下载进度的话,可以采用观察者模式来解耦。
实现步骤
1.定义一个观察者接口 interface Observer,观察者实现观察者接口 ObserverA implements Observer。
2.定义一个被观察者接口interface Subject,被观察者实现被观察者接口 SubjectDemo implements Subject。
3.在被观察者发生变化的时候,调用发送通知的方法,回调Observer里面的方法。
示例代码:
1.被观察者接口
public interface Subject {
//添加观察者
void addObserver(Observer observer);
//移除指定的观察者
void removeObserver(Observer observer);
//移除所有的观察者
void removeAll();
//通知所有观察者,data 是要通知给观察者的数据,Object是所有类的父类,可以使用多态,当然 你也可以使用 泛型
void notifyAllObserver(Object data);
//通知某一个观察者
void notify(Observer observer,Object data);
}
2.观察者接口
public interface Observer {
// 该方法是通知观察者更新
参数一:subject 是被观察者
参数二:data 是被观察者传递给观察者的 数据
void update(Subject subject,Object data);
}
3.实现接口,定义具体的被观察者与观察者
public class SubjectDemo implements Subject {
List mList = new ArrayList<>();
@Override
public void addObserver(Observer observer) {
// 确保相同的观察者只含有一个
if (observer == null) {
throw new NullPointerException(“observer == null”);
}
if (!mList.contains(observer)) {
mList.add(observer);
}
}
@Override
public void removeObserver(Observer observer) {
mList.remove(observer);
}
}
@Override
public void removeAll() {
mList.clear();
}
@Override
public void notifyAllObserver(Object data) {
for (Observer observer : mList) {
observer.update(this,data);
}
}
@Override
public void notify(Observer observer, Object data) {
if(observer!=null){
observer.update(this, data);
}
}
}
public class ObserverA implements Observer {
@Override
public void update(Subject subject, Object data) {
System.out.println( data+“我玩甄姬”);
}
}
![](/qrcode.jpg)
public class ObserverB implements Observer {
@Override
public void update(Subject subject, Object data) {
System.out.println( data+“我玩兰陵王”);
}
}
3.客户端调用
SubjectDemo subjectDemo = new SubjectDemo();
ObserverA observerA = new ObserverA();
ObserverB observerB = new ObserverB();
subjectDemo.addObserver(observerA);
subjectDemo.addObserver(observerB);
subjectDemo.notifyAllObserver(“今晚一起开黑”);
观察者优缺点
优点
很好地解耦了通知者与观察者,观察者不需要了解通知者内部是怎样实现的,方便于日后代码的修改,体现了 依赖倒转的原则。
缺点:
. 抽象通知者(即:被观察者接口Subject)还是依赖了抽象观察者(即:观察者接口Observer),当没有观察者的时候,没办法更新。因为Subject接口里有个添加观察者方法,该方法把Observer接口作为参数传入,否则通知不了观察者更新数据。
. 要求观察者的所有行为要一致。(即:具体的观察者必须实现观察者接口Observer里的所有方法)
什么是依赖倒转原则
简单的说,依赖倒转原则就是要求客户端依赖于抽象耦合,依赖倒转原则的表述是:抽象应当不依赖细节,细节应当依赖于抽象。另一种表述是:要针对接口编程,不要针对实现编程。
依赖关系种类:
1) 零耦合关系:如果两个类之间没有耦合关系,称之为零耦合
2) 具体耦合关系:具体耦合发生在两个具体类(可实例化的)之间,经由一个类对另一个类的直接引用造成。
3) 抽象耦合关系:抽象耦合关系发生在一个具体类和一个抽象类(或者java接口)之间,使两个必须发生关系的类之间存在最大的灵活性。
什么是EventBus
EventBus是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent、Handler、BroadCast在Fragment、Activity、Service、线程之间传递消息.优点是开销小,代码更优雅。做到多模块之间低耦合的事件通信,即将发送者和接收者解耦。
EventBus 3.0 之后方法名可以任意指定,不过需要添加 @Subscribe 注解,注解中可以指定线程模型、是否支持粘性事件、优先级。
粘性事件:先发送事件,再注册订阅者,也可以接受到事件。
普通事件:必须要订阅者先注册,然后发送事件,才能被订阅者接收到。
在 Android 下,线程的切换是一个很常用而且很必须的操作,EventBus 除了可以订阅和发送消息之外,它还可以指定接受消息处理消息的线程。
也就是说,无论你 post() 消息时处在什么线程中,EventBus 都可以将消息分发到你指定的线程上去,听上去就感觉非常的方便。
不过无论怎么切换,无外乎几种情况:
• UI 线程切子线程。
• 子线程切 UI 线程。
• 子线程切其他子线程。
在我们使用 EventBus 注册消息的时候,可以通过 @Subscribe 注解来完成注册事件, @Subscribe 中可以通过参数 threadMode 来指定使用那个线程来接收消息。
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventTest(event:TestEvent){
// 处理事件
}
threadMode 是一个 enum,有多种模式可供选择:
1. POSTING,默认值,那个线程发就是那个线程收。
2. MAIN,切换至主线程接收事件。
3. MAIN_ORDERED,v3.1.1 中新增的属性,也是切换至主线程接收事件,但是和 MAIN 有些许区别,如果事件就是在主线程中发送的,则使用 MAIN 会直接执行。为了让开发和可配置的程度更高,使用MAIN_ORDERED,它不会区分当前线程,而是通通使用 mainThreadPoster 来处理,也就是必然会走一遍 Handler 的消息分发。
4. BACKGROUND,确保在子线程中接收事件。细节就是,如果是主线程发送的消息,会切换到子线程接收,而如果事件本身就是由子线程发出,会直接使用发送事件消息的线程处理消息。
5. ASYNC,确保在子线程中接收事件,但是和 BACKGROUND 的区别在于,它不会区分发送线程是否是子线程,而是每次都在不同的线程中接收事件。
总之
- EventBus 可以通过 threadMode 来配置接收事件的线程。
- MAIN 和 MAIN_ORDERED 都会在主线程接收事件,区别在于是否区分,发生事件的线程是否是主线程。
- BACKGROUND 确保在子线程中接收线程,它会通过线程池,使用一个线程循环处理所有的事件。所以事件的执行时机,会受到事件队列前面的事件处理效率的影响。
- ASYNC 确保在子线程中接收事件,区别于 BACKGROUND,ASYNC 会每次向线程池中发送任务,通过线程池的调度去执行。但是因为线程池采用的是无界队列,会导致 ASYNC 待处理的事件太多时,会导致 OOM。
EventBus与观察者模式的关系
EventBus是基于观察者模式的消息处理框架。都是需要订阅时间,发布者发布信息,订阅者及时更新信息。
1.观察者模式的好处是更加的灵活,可以根据自己的需要定制属于自己业务的接口。同时在activity、fragment、service里面没有过多限制,完美解耦。
2.EventBus的好处是不需要再花大把时间去自己封装,提高了开发效率。