Subject 抽象主題角色:也就是抽象的被觀察者對象,裡面儲存了所有的觀察者對象引用列表,提供了註冊和反註冊的功能。 ConcreteSubject具體的主題角色:將有關狀態存入各ConcreteObserver對象 當它的狀態發送改變時,向它的各個觀察者發出通知 。 Observer 抽象觀察者 :為所有的具體觀察者定義一個介面,在得到通知時更新自己。 ConcreteObserver 具體觀察者:維護一個指向ConcreteObserver對象的引用 ,儲存有關狀態,這些狀態應與目標的狀態保持一致,實現Observer的更新介面是自身狀態與目標的狀態保持一致針對在android我們需要設計一個一個抽象的BaseObserverActivity,讓所有的Activity頁面都去繼承它,從本質上來看繼承這個類的所有的Activity都是一個觀察者,然後再觀察者對象中去定義需要監聽是什麼類型的事件和根據對應的事件的處理。
三.具體實現方案
(1)EventSubjectInterface:抽象的主題角色實現
/** * 抽象的主題角色 * @author zhiwu_yan * @since 2015年04月06日 * @version 1.0 */public interface EventSubjectInterface { /** * 註冊觀察者 * @param observer */ public void registerObserver(EventObserver observer); /** * 反註冊觀察者 * @param observer */ public void removeObserver(EventObserver observer); /** * 通知註冊的觀察者進行資料或者UI的更新 */ public void notifyObserver(String eventType);}主要包括了觀察者的註冊方法和反註冊方法以及通知觀察者去更新UI的方法,我們來看看具體的實現。
(2)EventSubject:具體的主題角色的實現
/** * 具體的主題角色的實現,這裡用來監聽事件的發生,採用單例模式來實現 * @author zhiwu_yan * @since 2015年04月06日 * @version 1.0 */public class EventSubject implements EventSubjectInterface{ private List mEventObservers=new ArrayList(); private static volatile EventSubject mEventSubject; private EventSubject(){ } public synchronized static EventSubject getInstance(){ if(mEventSubject ==null){ mEventSubject =new EventSubject(); } return mEventSubject; } @Override public void registerObserver(EventObserver observer) { synchronized (mEventObservers){ if(observer!=null){ if(mEventObservers.contains(observer)){ return; } mEventObservers.add(observer); } } } @Override public void removeObserver(EventObserver observer) { synchronized (mEventObservers){ int index = mEventObservers.indexOf(observer); if (index >= 0) { mEventObservers.remove(observer); } } } @Override public void notifyObserver(String eventType) { if(mEventObservers!=null && mEventObservers.size()>0 && eventType!=null){ for(EventObserver observer:mEventObservers){ observer.dispatchChange(eventType); } } }}裡面要注意的地方是:使用單例模式來控制只有一個主題角色,裡面儲存了所有的觀察者對象(EventObserver)列表,也就是護士手中的名單(見上一章),值得一提的是使用synchronized去控制多線程操作的問題。
(3)EventObserverInterface:抽象觀察者對象
/** * 觀察者介面 * @author zhiwu_yan * @since 2015年04月06日 * @version 1.0 */public interface EventObserverInterface { /** * 根據事件進行資料或者UI的更新 * @param eventType */ public void dispatchChange(String eventType);}裡面只有一個根據事件類型來跟新UI的方法,我們看看具體的抽象觀察者。
(4)EventObserver:具體的抽線觀察者
/** * 用於更新UI,這裡執行更新UI的onChange方法 * @author zhiwu_yan * @since 2015年04月06 * @version 1.0 */public abstract class EventObserver implements EventObserverInterface { private Handler mHandler; public EventObserver(){ mHandler=new Handler(Looper.getMainLooper()); } public abstract void onChange(String eventType); @Override public void dispatchChange(String eventType){ mHandler.post(new NotificationRunnable(eventType)); } private final class NotificationRunnable implements Runnable{ private String mEventType; public NotificationRunnable(String eventType){ this.mEventType=eventType; } @Override public void run() { EventObserver.this.onChange(mEventType); } }}我們定義了一個抽象的onChange方法交給子類去實現,這個方法就是用來處理對應的事件類型,比如需要重新整理資料等等。因為mHandler.post來跟新UI線程的,所以如果是耗時的操作需要另外開線程去處理。
(5)前面已經說過了,Android裡面我們需要定義一個帶觀察者模式的BaseActivity用來給某些需要監聽的業務的Activity使用,這樣只要繼承了該Activity的都是一個具體的觀察者對象。
/** * 帶有觀察者模式的Activity,本質上就是觀察者 * @author zhiwu_yan * @since 2015年04月6日 20:41 * @version 1.0 */public abstract class BaseObserverActivity extends ActionBarActivity { private ActivityEventObserver mActivityEventObserver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mActivityEventObserver=new ActivityEventObserver(this); registerObserver(mActivityEventObserver); } @Override protected void onDestroy() { super.onDestroy(); removeObserver(mActivityEventObserver); } public void registerObserver(EventObserver observer) { final String[] observerEventTypes=getObserverEventType();//擷取所有需要監聽的業務類型 if(observerEventTypes!=null && observerEventTypes.length>0){ final EventSubject eventSubject=EventSubject.getInstance(); eventSubject.registerObserver(observer); } } public void removeObserver(EventObserver observer) { final String[] observerEventTypes=getObserverEventType();//擷取所有需要監聽的業務類型 if(observerEventTypes!=null && observerEventTypes.length>0){ final EventSubject eventSubject=EventSubject.getInstance(); eventSubject.removeObserver(observer); } } /** * 該方法會在具體的觀察者對象中調用,可以根據事件的類型來更新對應的UI,這個方法在UI線程中被調用, * 所以在該方法中不能進行耗時操作,可以另外開線程 * @param eventType 事件類型 */ protected abstract void onChange(String eventType); /** * 通過這個方法來告訴具體的觀察者需要監聽的業務類型 * @return */ protected abstract String[] getObserverEventType(); private static class ActivityEventObserver extends EventObserver { //添加弱引用,防止對象不能被回收 private final WeakReference mActivity; public ActivityEventObserver(BaseObserverActivity activity){ super(); mActivity=new WeakReference(activity); } @Override public void onChange(String eventType) { BaseObserverActivity activity=mActivity.get(); if(activity!=null){ activity.onChange(eventType); } } }}另外我們需要定義一個可以動態擴充的事件類型:EventType
/** * 所有的業務類型,在這裡寫,方便管理 * @author zhiwu_yan * @since 2015年04月06日 * @version 1.0 */public class EventType { private static volatile EventType mEventType; private final static Set eventsTypes = new HashSet(); public final static String UPDATE_MAIN=com.updateMain; public final static String UPDATE_Text=com.updateText; private EventType(){ eventsTypes.add(UPDATE_MAIN); eventsTypes.add(UPDATE_Text); } public static EventType getInstance(){ if(mEventType==null){ mEventType=new EventType(); } return mEventType; } public boolean contains(String eventType){ return eventsTypes.contains(eventType); }}我這裡主要定義個2個事件類型,如果需要你可以定義N個事件類型,只要把你需要定義的事件添加到事件類別表裡面去就可以了。
我們在通知某個頁面需要更新的時候只需呀調用如下方法:
EventSubject eventSubject=EventSubject.getInstance(); EventType eventTypes=EventType.getInstance(); if(eventTypes.contains(eventType)){ eventSubject.notifyObserver(eventType); }為了便於管理我們也建立一個工具類:
/** * 通知中樞,用來通知更新資料或者UI,採用單例模式 * @author zhiwu_yan * @since 2015年04月6日 * @version 1.0 */public class Notify { private static volatile Notify mNotify; private Notify(){ } public static Notify getInstance(){ if(mNotify==null){ mNotify=new Notify(); } return mNotify; } public void NotifyActivity(String eventType){ EventSubject eventSubject=EventSubject.getInstance(); EventType eventTypes=EventType.getInstance(); if(eventTypes.contains(eventType)){ eventSubject.notifyObserver(eventType); } }}到這裡基本的架構就完成,我們看看怎麼使用。
四.使用方法
定義一個A頁面:MainActivity。這個頁面是一個觀察者,需要監聽來自其他頁面的一些通知,一旦有修改就根據對應的的事件來做出不同的處理:
public class MainActivity extends BaseObserverActivity { private TextView mLableTv; private ImageView mPicIv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLableTv=(TextView) findViewById(R.id.label_tv); mPicIv=(ImageView) findViewById(R.id.pic_iv); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id){ case R.id.go_other_activity: goActivity(OtherActivity.class); return true; } return super.onOptionsItemSelected(item); } private void goActivity(Class activity){ Intent intent=new Intent(this,activity); startActivity(intent); } @Override protected void onChange(String eventType) { if(EventType.UPDATE_MAIN==eventType){ mPicIv.setImageResource(R.mipmap.pic_two); }else if(EventType.UPDATE_Text==eventType){ mLableTv.setText(圖片被更新); } } @Override protected String[] getObserverEventType() { return new String[]{ EventType.UPDATE_MAIN, EventType.UPDATE_Text }; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); startActivityForResult(); }}主要看一下:onChange 方法:根據事件類型來更新不同的圖片,而在getObserverEventType()中我們定義了該觀察者需要觀察的業務類型,其它業務類型則會被忽略。
我們的B頁面:也就是發出通知的頁面,APP上面的設定頁面,唯一的作用就是通知觀察者:
public class OtherActivity extends ActionBarActivity { private Button mUpdateBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.other_activity); mUpdateBtn=(Button) findViewById(R.id.update_edit_btn); mUpdateBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Notify.getInstance().NotifyActivity(EventType.UPDATE_Text); Notify.getInstance().NotifyActivity(EventType.UPDATE_MAIN); } }); }}