接触安卓有一段时间了,之前一直都不懂什么设计模式之类的,
最近在做一个项目,从项目中理解到了一种观察者模式,个人
觉得这种观察者模式很好理解,也很好运用。
何为观察者模式?
观察者模式由 观察者 和 被观察者 组成。
简单的抽象成2种角色:观察角色、被观察角色。
观察角色时刻关注着被观察角色的动态,被观察角色一有动向就会向
观察角色发出一个通知,告诉它“我变化了”,你该做出相应的动作了。
观察者模式的应用与好处
场景:
MainActivity 跳转至 SecondActivity中修改资料,然后返回MainActivity。
好处:
实时更新修改的状态。
观察者接口:
public interface Watcher {
//被观察者改变通知更新
void update(WatchEnum watchEnum);
}
被观察者接口:
public interface Watched {
void addWatcher(Watcher watcher); // 添加观察者
void removeWatcher(Watcher watcher); // 移除观察者
void notifyWatchers(WatchEnum updateWatchEnum); // 通知观察者更新
void remoteWatchers(); // 清除观察者
}
由于一个被观察者可以被多个观察者关注,因此将观察者保存在List中。
被观察者具体实现:
public class ConcreteWatched implements Watched {
//存放观察者
private List<Watcher> list = new ArrayList<>();
private static ConcreteWatched concreteWatched;
//获取被观察者具体实现的实例
public static ConcreteWatched getInstance() {
if (concreteWatched == null) {
concreteWatched = new ConcreteWatched();
}
return concreteWatched;
}
@Override
public void addWatcher(Watcher watcher) {
list.add(watcher);
}
@Override
public void removeWatcher(Watcher watcher) {
list.remove(watcher);
}
@Override
public void notifyWatchers(WatchEnum updateWatchEnum) {
for (Watcher w : list) {
if (w != null) {
w.update(updateWatchEnum);
}
}
}
@Override
public void remoteWatchers() {
list.clear();
}
}
上述代码 notifyWatchers(WatchEnum updateWatchEnum) 中
的 WatchEnum 是一个枚举类,通过这个枚举类参数让被观察者
知道通知哪个观察者改变状态。
public enum WatchEnum {
TEXT1, TEXT2, TEXT3
}
此Demo中只列出了三个对象的改变,故枚举类中只有3个值。根据实际情况添加。
接下来说说Demo的具体实现:
在MainActivity中有3个TextView以及一个Button按钮,点击按钮跳转到
SecondActivity中,在SecondActivity中修改数据,点击返回键到MainActivity,可以看到MainActivity中三个TextView中显示数据发生了变化。
正常情况下,修改数据返回到ManActivity,数据显示是不会变化的。
以前还不懂观察者模式的时候,就只会利用Activity的生命周期,在
onResume方法中实现返回更新数据的效果,现在感觉这种方法实在
是太LOW。
注意:
1、由于是MainActivity的数据需要更新,因此需要实现 Watcher 接口,显示其 update 方法。
2、必须要将观察者添加到List中
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ConcreteWatched.getInstance().addWatcher(this); // important
}
一开始通过读取保存在SharedPrefreences文件中的数据。
private void setValue() {
String str1 = SPManager.getInstance().getString(this, SPManager.TXT1);
String str2 = SPManager.getInstance().getString(this, SPManager.TXT2);
String str3 = SPManager.getInstance().getString(this, SPManager.TXT3);
txt1.setText(str1);
txt2.setText(str2);
txt3.setText(str3);
}
当第一次为空的时候,默认显示“没有数据”。
public String getString(Context context, String key) {
SharedPreferences sharedPreferences = context.getSharedPreferences(WATCH_TEST, Activity.MODE_PRIVATE);
return sharedPreferences.getString(key, "没有数据");
}
当在SecondActivity中修改数据并保存后,返回后则会显示最新保存的数据。
public void alter1(View view) {
if (!TextUtils.isEmpty(edt1.getText().toString())) {
SPManager.getInstance().saveString(this, SPManager.TXT1, edt1.getText().toString());
ConcreteWatched.getInstance().notifyWatchers(WatchEnum.TEXT1); // 通知MainActivity中TextView1更新
Toast.makeText(this, "修改成功,请看返回键查看", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "不能为空", Toast.LENGTH_LONG).show();
}
}
以上是SecondActivity三个EditText中的一个修改方法。
ConcreteWatched.getInstance().notifyWatchers(WatchEnum.TEXT1);
这句代码起到通知观察者更新的作用。
还记得在MainActivity中实现的Watcher接口的实现方法update(WatchEnum)吗?
WatchEnum.TEXT1即为一个标志码,通知众多观察者具体的哪个。
再来看看MAinActivity中的代码:
@Override
public void update(WatchEnum watchEnum) {
switch (watchEnum) {
case TEXT1:
String str1 = SPManager.getInstance().getString(this, SPManager.TXT1);
txt1.setText(str1);
break;
}
}
就这样简简单单的Demo就能实现观察者的效果。
最后最好在一个Activity销毁的时候移除当前观察者;
@Override
protected void onDestroy() {
ConcreteWatched.getInstance().removeWatcher(this);
super.onDestroy();
}