本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Android中的观察者模式
观察者模式也是Android-Api中常用到的模式,它常用的地方是GUI系统、订阅——发布系统等,其模式重要特性就是解耦。
观察者模式的主要功能是让多个观察者同时监听某一个主题的变化,当监听的主题发生了变化,会通知所有的观察者,使得它们能更新自己。
定义观察者模式我们可以自定义实现,也可以使用继承Api的方式来实现:
一、自定义实现
自定义Observable 被观察主题对象
public class Observable<T> {
List<Observer<T>> mObservers = new ArrayList<Observer<T>>();
public void register(Observer<T> observer) {
if (observer == null) {
throw new NullPointerException("observer == null");
}
synchronized (this) {
if (!mObservers.contains(observer))
mObservers.add(observer);
}
}
public synchronized void unregister(Observer<T> observer) {
mObservers.remove(observer);
}
public void notifyObservers(T data) {
for (Observer<T> observer : mObservers) {
observer.onUpdate(this, data);
}
}
}
自定义Observer 观察者
public interface Observer<T> {
void onUpdate(Observable<T> observable,T data);
}
其实就通用于所有的观察者与被观察者之间的关联了,比如我们想观察天气对象,我们监听天气发生了变化,通知给每一个观察者做更新。
定义一个天气对象
public class Weather {
private String description;
public Weather(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
使用的时候:
Observable<Weather> observable=new Observable<Weather>();
Observer<Weather> observer1=new Observer<Weather>() { //直接构建出接口对象,匿名实现
@Override
public void onUpdate(Observable<Weather> observable, Weather data) {
System.out.println("观察者1:"+data.toString());
}
};
Observer<Weather> observer2=new Observer<Weather>() {
@Override
public void onUpdate(Observable<Weather> observable, Weather data) {
System.out.println("观察者2:"+data.toString());
}
};
observable.register(observer1);
observable.register(observer2);
Weather weather=new Weather("晴转多云");
observable.notifyObservers(weather);
Weather weather1=new Weather("多云转阴");
observable.notifyObservers(weather1);
observable.unregister(observer1);
Weather weather2=new Weather("台风");
打印
观察者1:Weather{description=’晴转多云’}
观察者2:Weather{description=’晴转多云’}
观察者1:Weather{description=’多云转阴’}
观察者2:Weather{description=’多云转阴’}
观察者2:Weather{description=’台风’}
二、继承Api的实现
Java的Api中就有观察者模式的定义 java.util.Observable 类和 java.util.Observer 接口,这分别对应着 Subject 和 Observer 的角色。
需要注意的是被观察者在调用 notifyObservers() 函数通知观察者之前一定要调用 setChanged() 函数,要不然观察者无法接到通知
例如我们定义一个被观察者 Observable
public class MyPerson extends Observable {
private String name;
private int age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
setChanged();
notifyObservers();
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
setChanged();
notifyObservers();
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
setChanged();
notifyObservers();
}
@Override
public String toString() {
return "MyPerson [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
}
定义一个观察者 Observer
public class MyObserver implements Observer {
private int id;
private MyPerson myPerson;
public MyObserver(int id) {
System.out.println("我是观察者---->" + id);
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public MyPerson getMyPerson() {
return myPerson;
}
public void setMyPerson(MyPerson myPerson) {
this.myPerson = myPerson;
}
@Override
public void update(Observable observable, Object data) {
System.out.println("观察者---->" + id + "得到更新");
this.myPerson = (MyPerson) observable;
System.out.println(((MyPerson) observable).toString());
}
}
通过 setChanged() 告知数据改变,
通过 notifyObservers() 发送信号通知观察者。
使用:
MyObserver observable = new MyPerson() //被观察者
observable.addObserver(new MyObserver(0)); //添加多个观察者
observable.addObserver(new MyObserver(1));
observable.setName("a" + i);
observable.setAge(10 + i);
observable.setSex("男" + i);
//被观察者内部每一个set方法内部都做了setChanged(); notifyObservers(); 所以观察者可以收到消息,观察者的update()方法可以正常收到消息,打印消息
总结
观察者模式在Android源码和一些第三方库都使用的比较广泛,如ListView RecyclerView BroadcastReceiver EventBus等。
使用场景为:当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。
注意点:
在使用时要考虑开发效率和运行效率,程序中包括一个被观察者、多个观察者、开发调试等内容会比较复杂,且Java中消息通知默认是顺序执行,如果一个观察者卡顿,那么会影响整体执行效率,在这种情况下一般考虑使用异步的方式。
好了简单的使用就到处为主,后面会将一些实用技巧哦