1. 定義谎痢?
當(dāng)一個(gè)對象的狀態(tài)發(fā)生改變時(shí),與他相關(guān)聯(lián)的部分對象的狀態(tài)同時(shí)也會(huì)發(fā)生改變。
比如訂閱公眾號(hào):
- 比如我訂閱了鴻陽的微信公眾號(hào),只要他每更新一篇文章都會(huì)及時(shí)的通知我 [觀察者設(shè)計(jì)模式]渠羞;
對應(yīng)上邊定義就是:一個(gè)對象的狀態(tài)發(fā)生改變時(shí),就是鴻陽公眾號(hào)有文章更新智哀,由于我訂閱了該公眾號(hào)次询,所以說我的部分狀態(tài)也會(huì)發(fā)生改變,比如我會(huì)去看該公眾號(hào)更新的文章盏触;
EventBus:和觀察者設(shè)計(jì)模式?jīng)]有半毛錢關(guān)系
2. 角色劃分?
被觀察者(Observable):公眾號(hào)块饺;
具體的被觀察者(Concreate Observable):鴻陽公眾號(hào)赞辩;
觀察者(Observer):微信用戶;
具體的觀察者(Concreate Observer):我授艰,Novate
3. 示例代碼 - 訂閱公眾號(hào)辨嗽?
寫一個(gè)事例代碼
被觀察者:WXPublicObservable(公眾號(hào));
具體的被觀察者:WXAdvanceObservable(鴻陽的公眾號(hào))淮腾;
觀察者:IWXUser(微信用戶)糟需;
具體的觀察者:WXUser(Novate、WangZiWen)谷朝;
4. 示例代碼如下
1>:WXPublicObservable洲押,被觀察者 - 微信公眾號(hào)
/**
* Email: 2185134304@qq.com
* Created by Novate 2018/5/27 15:03
* Version 1.0
* Params:
* Description: 微信公眾號(hào) - 多個(gè)人去訂閱的公眾號(hào)
*/
public class WXPublicObservable {
// 所有訂閱用戶的集合
private List<IWXUser> mWXUsers ;
public WXPublicObservable(){
mWXUsers = new ArrayList<>() ;
}
/**
* 訂閱
*/
public void register(IWXUser wxUser){
mWXUsers.add(wxUser) ;
}
/**
* 取消訂閱
*/
public void unregister(IWXUser wxUser){
mWXUsers.remove(wxUser) ;
}
/**
* 文章更新
*/
public void update(String article){
// 推送所有更新的文章
for (IWXUser wXUser : mWXUsers) {
wXUser.push(article);
}
}
}
2>:WXAdvanceObservable,具體的被觀察者 - 鴻陽的微信公眾號(hào)
/**
* Email: 2185134304@qq.com
* Created by Novate 2018/5/27 15:12
* Version 1.0
* Params:
* Description: 具體的被觀察者 - 鴻陽的微信公眾號(hào)
*/
public class WXAdvanceObservable extends WXPublicObservable{
private String article ;
public String getArticle() {
return article;
}
public void setArticle(String article) {
this.article = article;
// 通知更新圆凰,推送給微信用戶
update(article);
}
}
3>:IWXUser杈帐,接口,微信用戶专钉;
/**
* Email: 2185134304@qq.com
* Created by Novate 2018/5/27 15:06
* Version 1.0
* Params:
* Description: 微信用戶 - 訂閱該微信公眾號(hào)
*/
public interface IWXUser {
/**
* 讀文章
*/
void push(String article) ;
}
4>:WXUser挑童,具體的觀察者,具體的用戶跃须,訂閱鴻陽微信公眾號(hào)的用戶
/**
* Email: 2185134304@qq.com
* Created by Novate 2018/5/27 15:14
* Version 1.0
* Params:
* Description: 具體的用戶 - 訂閱鴻陽的微信公眾號(hào)
*/
public class WXUser implements IWXUser{
private String name ;
public WXUser(String name){
this.name = name ;
}
@Override
public void push(String article) {
System.out.println(name+"收到了一篇文章:"+article);
}
}
5>:創(chuàng)建具體的被觀察者和具體的觀察者對象站叼,測試代碼如下:
/**
* Email: 2185134304@qq.com
* Created by Novate 2018/5/27 15:16
* Version 1.0
* Params:
* Description:
*/
public class Client {
public static void main(String[] args){
// 具體的被觀察者 - 微信公眾號(hào) - 鴻陽的公眾號(hào)
WXAdvanceObservable wxAdvanceObservable = new WXAdvanceObservable() ;
// 具體的觀察者 - 微信公眾號(hào) - Novate
WXUser novate = new WXUser("novate") ;
WXUser wangziwen = new WXUser("wangziwen") ;
// 微信公眾號(hào) - 用戶訂閱公眾號(hào)
wxAdvanceObservable.register(novate);
wxAdvanceObservable.register(wangziwen);
// 微信公眾號(hào) - 推送文章
wxAdvanceObservable.setArticle("《觀察者設(shè)計(jì)模式 - 定義及事例代碼》");
// 微信公眾號(hào) - 用戶取消訂閱公眾號(hào)
wxAdvanceObservable.unregister(wangziwen);
}
}
運(yùn)行結(jié)果打印如下
5. 源碼中觀察者設(shè)計(jì)模式的使用場景
1>:RxJava源碼;
2>:ListView的 Adapter的setDataChange的方法菇民;
6. ListView部分源碼分析
1>:ListView中的setAdapter()方法
@Override
public void setAdapter(ListAdapter adapter) {
// 防止多次調(diào)用setAdapter尽楔,而不去調(diào)用notifyDataSetChanged
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
// 給adapter注冊一個(gè) mDataSetObserver
mAdapter.registerDataSetObserver(mDataSetObserver);
//
requestLayout();
}
2>:只要調(diào)用了 adapter.notifyDataSetChanged()方法投储,就會(huì)執(zhí)行下邊代碼:
A:BaseAdapter中的notifyDataSetChanged():
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
/**
* Notifies the attached observers that the underlying data has been changed
* and any View reflecting the data set should refresh itself.
*/
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
B:然后調(diào)用
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
// 只要一更新,就會(huì)調(diào)用onChanged()翔试,
// 所以其實(shí)是用 onChanged()方法把 ListView與adapter進(jìn)行關(guān)聯(lián)
mObservers.get(i).onChanged();
}
}
}
3>:這個(gè)時(shí)候會(huì)來到AdapterView的onChanged()方法轻要,來更新ListView;
class AdapterDataSetObserver extends DataSetObserver {
private Parcelable mInstanceState = null;
@Override
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = getAdapter().getCount();
// Detect the case where a cursor that was previously invalidated has
// been repopulated with new data.
if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
&& mOldItemCount == 0 && mItemCount > 0) {
AdapterView.this.onRestoreInstanceState(mInstanceState);
mInstanceState = null;
} else {
rememberSyncState();
}
checkFocus();
// 重新執(zhí)行onMeasure()垦缅、onLayout()冲泥、onDraw()這幾個(gè)方法
requestLayout();
}
@Override
public void onInvalidated() {
mDataChanged = true;
checkFocus();
requestLayout();
}
public void clearSavedState() {
mInstanceState = null;
}
}
7. ListView觀察者設(shè)計(jì)模式圖解
由以上分析ListView觀察者設(shè)計(jì)模式圖解可知:
1>:ListView與adapter二者其實(shí)關(guān)聯(lián)不太大壁涎,ListView只是調(diào)用了setAdapter()方法凡恍,那么adapter如果數(shù)據(jù)改變?nèi)绾瓮ㄖ狶istView刷新界面,比如adapter少了一條數(shù)據(jù)怔球,就需要ListView少顯示一條數(shù)據(jù)嚼酝;
2>:其實(shí)在ListView調(diào)用setAdapter()時(shí)候,會(huì)給它的adapter中注冊一群觀察者竟坛,也就是說ListView中有 Observer闽巩,adapter中有一群Observable,也就是說有多個(gè)Observable担汤,把ListView中的Observer注冊到adapter中的Observable涎跨,也就是說把ListView的對象注冊到adapter中的Observable中;
3>:只要調(diào)用了 notifySetDataChanged()崭歧,這個(gè)時(shí)候adapter中所有的 Observable會(huì)進(jìn)行for循環(huán)來調(diào)用 Observer中的onChanged()方法隅很;
4>:然后在AdapterView中,調(diào)用onChanged()方法率碾,然后再調(diào)用 requestLayout()方法叔营,重新執(zhí)行onMeasure()、onLayout()所宰、onDraw()方法绒尊;