接触安卓有一段时间了,之前一直都不懂什么设计模式之类的, 最近在做一个项目,从项目中理解到了一种观察者模式,个人 觉得这种观察者模式很好理解,也很好运用。
何为观察者模式?
观察者模式由 观察者 和 被观察者 组成。
简单的抽象成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(); }完整代码:完整Demo下载