Android源碼學習之觀察者模式應用及優(yōu)點介紹
更新時間:2013年01月06日 12:17:01 作者:
定義對象間一種一對多的依賴關系,使得當一個對象改變狀態(tài),則所有依賴于它的對象都會得到通知并被自動更新等等,需要了解的朋友可以參考下
觀察者模式定義:
Define a one-to-many dependency between objects so that when one object changes state, all its dependents aer notified and updated automatically.
定義對象間一種一對多的依賴關系,使得當一個對象改變狀態(tài),則所有依賴于它的對象都會得到通知并被自動更新。
如上圖所示(截取自《Head First Design Patterns》一書),主要包括四個部分:
1. Subject被觀察者。是一個接口或者是抽象類,定義被觀察者必須實現(xiàn)的職責,它必須能偶動態(tài)地增加、取消觀察者,管理觀察者并通知觀察者。
2. Observer觀察者。觀察者接收到消息后,即進行update更新操作,對接收到的信息進行處理。
3. ConcreteSubject具體的被觀察者。定義被觀察者自己的業(yè)務邏輯,同時定義對哪些事件進行通知。
4. ConcreteObserver具體觀察者。每個觀察者在接收到信息后處理的方式不同,各個觀察者有自己的處理邏輯。
觀察者模式有什么優(yōu)點呢:
觀察者和被觀察者之間是抽象耦合的,不管是增加觀察者還是被觀察者都非常容易擴展。
根據(jù)單一職責原則,每個類的職責是單一的,那么怎么把各個單一的職責串聯(lián)成真實的復雜的邏輯關系呢,觀察者模式可以起到橋梁作用。
觀察者模式是松耦合的典型。
在Android源碼中,其中一個經典的使用到觀察者模式的就是Android控件的事件監(jiān)聽模型。
一、下面簡要說明Android交互事件傳輸?shù)脑O計原理和特征:
交互事件,是指當用戶通過按鍵、觸摸、滑動等操作與應用進行交互時觸發(fā)的相關事件。通過Android控件樹可知,交互事件是沿著控件樹自頂向下傳播的。其中Android控件樹簡要圖如下所示:
當位于控件樹上層的父控件收到交互事件后,會先行判定該事件的目標控件對象,如果該事件正是自己所需要的,則會截獲事件進行處理,否則就嘗試將事件向下分發(fā)給對應的子控件,并對推的逐級向下傳播事件,直至該事件被處理或者忽略。
Android在View類中定義了一系列命名為View.On***的事件函數(shù)用來接收和處理各類交互事件,如通過View.OnKeyDown函數(shù)可以接收到用戶的按鍵操作等。每個派生自View類的子控件都可以通過重載這些事件函數(shù),來處理該控件所需的事件。
例如,如果一個控件需要處理用戶按返回鍵的操作,則可以通過重載View.onKeyDown函數(shù)來實現(xiàn):
/*
* @see android.app.Activity#onKeyDown(int, android.view.KeyEvent)
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 監(jiān)聽和處理返回操作
if(keyCode == KeyEvent.KEYCODE_BACK) {
doSomething();
return true;
}
return false;
}
事件函數(shù)的返回值是控制事件傳播的重要手段。如果事件函數(shù)返回true,則說明該控件已經接收并完成了該事件的處理,無須將該事件進一步傳遞;反之,如果事件函數(shù)返回false,則說明該控件對象未能處理該事件(或雖然做過處理,但仍需要進一步處理),需要繼續(xù)傳遞以尋找能夠處理它的控件對象。
對于容器控件ViewGroup來說,它的一個職責就是將交互事件傳播到其子控件中。針對不同的事件,ViewGroup可以選擇不同的傳播方式。如,如果是觸摸事件,ViewGroup對象需要判定該事件發(fā)生的區(qū)域位于哪個子控件上,從而將該事件分配給該子控件進行處理。但通過繼承的方式來進行事件處理并不夠靈活,會導致系統(tǒng)中出現(xiàn)大量的子控件類型,并且各個控件的復用性都較差。因此采用“組合”來代替“繼承”?;诖怂枷?,View類中提供了一系列配套的事件監(jiān)聽函數(shù)供開發(fā)者處理對應事件,這就有了使用觀察者模式來完成Android控件的事件監(jiān)聽模型。開發(fā)者可以構造外部觀察者對象與控件對象的事件監(jiān)聽接口綁定,獲取事件消息。
還是以上面的按鍵事件為例,通過監(jiān)聽者進行處理的實現(xiàn)如下所示:
final View.OnKeyListener listener = new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// 處理返回鍵事件
if(keyCode == KeyEvent.KEYCODE_BACK) {
doSomething();
return true;
}
return false;
}
};
。。。
mUISetButton = (Button) findViewById(R.id.setValue);
// 將按鈕與監(jiān)聽對象綁定
mUISetButton.setOnKeyListener(listener);
通過利用外部對象來處理交互事件,其耦合性低,使每個類控件都具有更好的可復用度,無須為了處理事件而構造新的控件。
二、現(xiàn)在開始看看源代碼是怎么進行組織使用“觀察者模式”的
1. 看View類源代碼中的OnKeyListener接口:
/**
* Interface definition for a callback to be invoked when a key event is
* dispatched to this view. The callback will be invoked before the key
* event is given to the view.
*/
public interface OnKeyListener {
/**
* Called when a key is dispatched to a view. This allows listeners to
* get a chance to respond before the target view.
*
* @param v The view the key has been dispatched to.
* @param keyCode The code for the physical key that was pressed
* @param event The KeyEvent object containing full information about
* the event.
* @return True if the listener has consumed the event, false otherwise.
*/
boolean onKey(View v, int keyCode, KeyEvent event);
}
2. 再看View類定義了私有成員mOnKeyListener(通過組合的方式):
private OnKeyListener mOnKeyListener;
3. 注冊listener
/**
* Register a callback to be invoked when a key is pressed in this view.
* @param l the key listener to attach to this view
*/
public void setOnKeyListener(OnKeyListener l) {
mOnKeyListener = l;
}
4. 剩下的就交給開發(fā)者自己構造外部觀察者對象與該按鍵的事件接口進行綁定,獲取事件消息。
最后讓我們記住支撐“觀察者模式”的設計原則: Strive for loosely coupled designs between objects that interact.
Define a one-to-many dependency between objects so that when one object changes state, all its dependents aer notified and updated automatically.
定義對象間一種一對多的依賴關系,使得當一個對象改變狀態(tài),則所有依賴于它的對象都會得到通知并被自動更新。

如上圖所示(截取自《Head First Design Patterns》一書),主要包括四個部分:
1. Subject被觀察者。是一個接口或者是抽象類,定義被觀察者必須實現(xiàn)的職責,它必須能偶動態(tài)地增加、取消觀察者,管理觀察者并通知觀察者。
2. Observer觀察者。觀察者接收到消息后,即進行update更新操作,對接收到的信息進行處理。
3. ConcreteSubject具體的被觀察者。定義被觀察者自己的業(yè)務邏輯,同時定義對哪些事件進行通知。
4. ConcreteObserver具體觀察者。每個觀察者在接收到信息后處理的方式不同,各個觀察者有自己的處理邏輯。
觀察者模式有什么優(yōu)點呢:
觀察者和被觀察者之間是抽象耦合的,不管是增加觀察者還是被觀察者都非常容易擴展。
根據(jù)單一職責原則,每個類的職責是單一的,那么怎么把各個單一的職責串聯(lián)成真實的復雜的邏輯關系呢,觀察者模式可以起到橋梁作用。
觀察者模式是松耦合的典型。
在Android源碼中,其中一個經典的使用到觀察者模式的就是Android控件的事件監(jiān)聽模型。
一、下面簡要說明Android交互事件傳輸?shù)脑O計原理和特征:
交互事件,是指當用戶通過按鍵、觸摸、滑動等操作與應用進行交互時觸發(fā)的相關事件。通過Android控件樹可知,交互事件是沿著控件樹自頂向下傳播的。其中Android控件樹簡要圖如下所示:

當位于控件樹上層的父控件收到交互事件后,會先行判定該事件的目標控件對象,如果該事件正是自己所需要的,則會截獲事件進行處理,否則就嘗試將事件向下分發(fā)給對應的子控件,并對推的逐級向下傳播事件,直至該事件被處理或者忽略。
Android在View類中定義了一系列命名為View.On***的事件函數(shù)用來接收和處理各類交互事件,如通過View.OnKeyDown函數(shù)可以接收到用戶的按鍵操作等。每個派生自View類的子控件都可以通過重載這些事件函數(shù),來處理該控件所需的事件。
例如,如果一個控件需要處理用戶按返回鍵的操作,則可以通過重載View.onKeyDown函數(shù)來實現(xiàn):
復制代碼 代碼如下:
/*
* @see android.app.Activity#onKeyDown(int, android.view.KeyEvent)
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 監(jiān)聽和處理返回操作
if(keyCode == KeyEvent.KEYCODE_BACK) {
doSomething();
return true;
}
return false;
}
事件函數(shù)的返回值是控制事件傳播的重要手段。如果事件函數(shù)返回true,則說明該控件已經接收并完成了該事件的處理,無須將該事件進一步傳遞;反之,如果事件函數(shù)返回false,則說明該控件對象未能處理該事件(或雖然做過處理,但仍需要進一步處理),需要繼續(xù)傳遞以尋找能夠處理它的控件對象。
對于容器控件ViewGroup來說,它的一個職責就是將交互事件傳播到其子控件中。針對不同的事件,ViewGroup可以選擇不同的傳播方式。如,如果是觸摸事件,ViewGroup對象需要判定該事件發(fā)生的區(qū)域位于哪個子控件上,從而將該事件分配給該子控件進行處理。但通過繼承的方式來進行事件處理并不夠靈活,會導致系統(tǒng)中出現(xiàn)大量的子控件類型,并且各個控件的復用性都較差。因此采用“組合”來代替“繼承”?;诖怂枷?,View類中提供了一系列配套的事件監(jiān)聽函數(shù)供開發(fā)者處理對應事件,這就有了使用觀察者模式來完成Android控件的事件監(jiān)聽模型。開發(fā)者可以構造外部觀察者對象與控件對象的事件監(jiān)聽接口綁定,獲取事件消息。
還是以上面的按鍵事件為例,通過監(jiān)聽者進行處理的實現(xiàn)如下所示:
復制代碼 代碼如下:
final View.OnKeyListener listener = new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// 處理返回鍵事件
if(keyCode == KeyEvent.KEYCODE_BACK) {
doSomething();
return true;
}
return false;
}
};
。。。
mUISetButton = (Button) findViewById(R.id.setValue);
// 將按鈕與監(jiān)聽對象綁定
mUISetButton.setOnKeyListener(listener);
通過利用外部對象來處理交互事件,其耦合性低,使每個類控件都具有更好的可復用度,無須為了處理事件而構造新的控件。
二、現(xiàn)在開始看看源代碼是怎么進行組織使用“觀察者模式”的
1. 看View類源代碼中的OnKeyListener接口:
復制代碼 代碼如下:
/**
* Interface definition for a callback to be invoked when a key event is
* dispatched to this view. The callback will be invoked before the key
* event is given to the view.
*/
public interface OnKeyListener {
/**
* Called when a key is dispatched to a view. This allows listeners to
* get a chance to respond before the target view.
*
* @param v The view the key has been dispatched to.
* @param keyCode The code for the physical key that was pressed
* @param event The KeyEvent object containing full information about
* the event.
* @return True if the listener has consumed the event, false otherwise.
*/
boolean onKey(View v, int keyCode, KeyEvent event);
}
2. 再看View類定義了私有成員mOnKeyListener(通過組合的方式):
private OnKeyListener mOnKeyListener;
3. 注冊listener
復制代碼 代碼如下:
/**
* Register a callback to be invoked when a key is pressed in this view.
* @param l the key listener to attach to this view
*/
public void setOnKeyListener(OnKeyListener l) {
mOnKeyListener = l;
}
4. 剩下的就交給開發(fā)者自己構造外部觀察者對象與該按鍵的事件接口進行綁定,獲取事件消息。
最后讓我們記住支撐“觀察者模式”的設計原則: Strive for loosely coupled designs between objects that interact.
相關文章
Android仿微信底部菜單欄功能顯示未讀消息數(shù)量
這篇文章主要介紹了Android仿微信底部菜單欄功能,并顯示未讀消息數(shù)量,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-05-05Android Studio 3.x版本 的輸入法遇到的坑及解決方案
前些天把AndroidStudio從2.3.3升級到3.0,遇到了不少坑,其中一個巨坑就是輸入中文不提示的問題,下面給大家分享Android Studio 3.x版本的輸入法遇到的坑及解決方案,一起看看吧2017-11-11Android中用RxJava和ViewPager實現(xiàn)輪播圖
現(xiàn)在App中實現(xiàn)一個輪播圖已經是很多產品的標配了,這篇文章給大家詳細介紹了如何利用RxJava和ViewPager實現(xiàn)輪播圖,有需要的朋友們可以參考借鑒,下面來一起看看吧。2016-09-09Android開發(fā)之HttpClient異步請求數(shù)據(jù)的方法詳解【附demo源碼下載】
這篇文章主要介紹了Android開發(fā)之HttpClient異步請求數(shù)據(jù)的方法,結合實例形式較為詳細的分析了Android HttpClient異步請求數(shù)據(jù)的相關操作技巧,并附帶完整demo源碼供讀者下載參考,需要的朋友可以參考下2017-11-11Android自定義控件ImageView實現(xiàn)點擊之后出現(xiàn)陰影效果
這篇文章主要為大家詳細介紹了Android自定義控件ImageView實現(xiàn)點擊之后有陰影效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-12-12Android實現(xiàn)系統(tǒng)狀態(tài)欄的隱藏和顯示功能
這篇文章主要介紹了Android實現(xiàn)系統(tǒng)狀態(tài)欄的隱藏和顯示功能,文中還給大家?guī)硭姆N方法,大家可以根據(jù)自己需要參考下2018-07-07AndroidStudio代碼達到指定字符長度時自動換行實例
這篇文章主要介紹了AndroidStudio代碼達到指定字符長度時自動換行實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03