編輯:關於Android編程
在上一篇文章中介紹了介紹了觀察者模式的定義和一些基本概念,觀察者模式在 android開發中應用還是非常廣泛的,例如android按鈕事件的監聽、廣播等等,在任何類似於新聞-訂閱的模式下面都可以使用。從某種意義上面來說android有點像JAVA EE的WEB頁面,在都需要提供View層用於進行操作,在多個頁面之間傳遞數據發送通知都是一件很麻煩的事情。
在android中從A頁面跳轉到B頁面,然後B頁面進行某些操作後需要通知A頁面去刷新數據,我們可以通過startActivityForResult來喚起B頁面,然後再B頁面結束後在A頁面重寫onActivityResult來接收返回結果從而來刷新頁面。但是如果跳轉路徑是這樣的A->B->C->.....,C或者C以後的頁面來刷新A,這個時候如果還是使用這種方法就會非常的棘手。使用這種方法可能會存在以下幾個弊端:
因此考慮使用觀察者模式去處理這個問題。
在APP中我們有一些設置項目,我們希望在設置完了以後,在主頁面能夠立即響應,例如QQ的清空聊天記錄,我們希望設置了以後回到主頁面後會自動清理,有些人可能會認為這是一件很簡單的事情,認為回到主頁面直接讀緩存就好了,緩存裡面是什麼就是什麼,課時這種方案存在2個問題:
因此行功能和代碼結構上面來看我的需求主要有以下幾點:
從上一篇文章中我們知道一個完整的觀察者模式需要這些對象:

針對在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);
}
});
}
}
android百度地圖 添加覆蓋物Marker與InfoWindow的使用
如何添加覆蓋物,實現周邊搜索,以及對覆蓋物的點擊出現介紹等效果。效果圖:我們的需求是,當用戶點擊衣食住行,或者對對附近搜索是,從服務器返回數據(經緯度,商家信息,介紹等)
Android中Service 全解析
在學習Android四大模塊的時候在service的學習是必須要掌握的,而且個人感覺相當重要!很多場合都有需要的!首先我們看看Service的種類按運行地點分類 以上面三
Android Activity啟動模式之singleTask實例詳解
本文實例分析了Android Activity啟動模式之singleTask。分享給大家供大家參考,具體如下:前面的文章介紹了Android 活動Activity的啟動模
Android 性能分析工具之 TraceView 使用說明
TraceView 是 Android 平台配備一個很好的性能分析的工具。它可以通過圖形化的方式讓我們了解我們要跟蹤的程序的性能,並且能具體到 method。TraceV