編輯:Android資訊
定義對象間一種一對多的依賴關系,使得每當一個對象改變狀態,則所有依賴於它的對象都會得到通知並被自動更新。
AndroidWeekly是一個每周都會發布關於Android新技術、開源庫、招聘信息等內容的網站,在這裡我們可以看到最新的技術,最牛X的工程師,經常逛逛這類網站不僅能夠開闊我們的眼界,也能讓我們接觸到最前言的科技信息。這其實就是一個RSS系統,用戶訂閱Android Weekly的文章,每當有更新的時候將新的內容推送給訂閱用戶。這不就是觀察者模式嗎?觀察者模式的另一個名字叫做發布-訂閱模式,下圖就是我訂閱AndroidWeekly之後他們發來的確認郵件。下面讓我們來簡單模擬一下AndroidWeekly的發布過程吧!
/** * 程序員是觀察者 * * @author mrsimple */ public class Coder implements Observer { public String name ; public Coder(String aName) { name = aName ; } @Override public void update(Observable o, Object arg) { System.out.println( "Hi, " + name + ", AndroidWeekly更新啦, 內容 : " + arg); } @Override public String toString() { return "碼農 : " + name; } } /** * AndroidWeekly這個網站是被觀察者,它有更新所有的觀察者 (這裡是程序員) 都會接到相應的通知. * * @author mrsimple */ public class AndroidWeekly extends Observable { public void postNewPublication(String content) { // 標識狀態或者內容發生改變 setChanged(); // 通知所有觀察者 notifyObservers(content); } } // 測試代碼 public class Test { public static void main(String[] args) { // 被觀察的角色 AndroidWeekly androidWeekly = new AndroidWeekly(); // 觀察者 Coder mrsimple = new Coder("mr.simple"); Coder coder1 = new Coder("coder-1"); Coder coder2 = new Coder("coder-2"); Coder coder3 = new Coder("coder-3"); // 將觀察者注冊到可觀察對象的觀察者列表中 androidWeekly.addObserver(mrsimple); androidWeekly.addObserver(coder1); androidWeekly.addObserver(coder2); androidWeekly.addObserver(coder3); // 發布消息 androidWeekly.postNewPublication("新的一期AndroidWeekly來啦!"); } }
輸入結果:
Hi, coder-3, AndroidWeekly更新啦, 內容 : 新的一期AndroidWeekly來啦! Hi, coder-2, AndroidWeekly更新啦, 內容 : 新的一期AndroidWeekly來啦! Hi, coder-1, AndroidWeekly更新啦, 內容 : 新的一期AndroidWeekly來啦! Hi, mr.simple, AndroidWeekly更新啦, 內容 : 新的一期AndroidWeekly來啦!
可以看到所有訂閱了AndroidWeekly的用戶都受到了更新消息,一對多的訂閱-發布系統這麼簡單就完成了。
這裡Observer是抽象的觀察者角色,Coder扮演的是具體觀察者的角色;Observable對應的是抽象主題角色,AndroidWeekly則是具體的主題角色。Coder是具體的觀察者,他們訂閱了AndroidWeekly這個具體的可觀察對象,當AndroidWeekly有更新時,會遍歷所有觀察者 ( 這裡是Coder碼農 ),然後給這些觀察者發布一個更新的消息,即調用Coder中的update方法,這樣就達到了1對多的通知功能。Observer和Observable都已經內置在jdk中,可見觀察者模式在java中的重要性。
ListView是Android中最重要的控件,沒有之一。而ListView最重要的一個點就是Adapter,在Android設計模式源碼解析之適配器(Adapter)模式中我們分析了Adapter模式,在我們往ListView添加數據後,我們都會調用一個方法: notifyDataSetChanged(), 這是為什麼呢? 今天我們就來揭開它的神秘面紗。
第一步我們就跟進這個方法notifyDataSetChanged方法,這個方法定義在BaseAdapter中,代碼如下:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { // 數據集觀察者 private final DataSetObservable mDataSetObservable = new DataSetObservable(); // 代碼省略 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(); } }
我們一看BaseAdapter上述代碼,大體有了這麼一個了解,原來BaseAdapter是一個觀察者模式!
那麼BaseAdapter是如何運作的? 這些觀察者又是什麼呢?我們一步一步來分析。
我們先跟到mDataSetObservable.notifyChanged()函數中看看。
/** * A specialization of Observable for DataSetObserver that provides methods for * invoking the various callback methods of DataSetObserver. */ public class DataSetObservable extends Observable<DataSetObserver> { /** * Invokes onChanged on each observer. Called when the data set being observed has * changed, and which when read contains the new state of the data. */ public void notifyChanged() { synchronized(mObservers) { // 調用所有觀察者的onChanged方式 for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } } // 代碼省略 }
恩,代碼很簡單,就是在mDataSetObservable.notifyChanged()中遍歷所有觀察者,並且調用它們的onChanged方法。
那麼這些觀察者是從哪裡來的呢?首先ListView通過setAdapter方法來設置Adapter,我們看看相關代碼。
@Override public void setAdapter(ListAdapter adapter) { // 如果已經有了一個adapter,那麼先注銷該Adapter對應的觀察者 if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); } // 代碼省略 super.setAdapter(adapter); if (mAdapter != null) { mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); mOldItemCount = mItemCount; // 獲取數據的數量 mItemCount = mAdapter.getCount(); checkFocus(); // 注意這裡 : 創建一個一個數據集觀察者 mDataSetObserver = new AdapterDataSetObserver(); // 將這個觀察者注冊到Adapter中,實際上是注冊到DataSetObservable中 mAdapter.registerDataSetObserver(mDataSetObserver); // 代碼省略 } else { // 代碼省略 } requestLayout(); }
可以看到在設置Adapter時會構建一個AdapterDataSetObserver,這不就是我們上面所說的觀察者麼,最後將這個觀察者注冊到adapter中,這樣我們的被觀察者、觀察者都有了。一般來說我們的數據集會放到Adapter中,例如 :
public abstract class UserAdapter extends BaseAdapter { // 數據集 protected List<String> mDataSet = new LinkedList<String>(); protected Context mContext = null; public CommonAdapter(Context context, List<String> dataSet) { this.mDataSet = dataSet; this.mContext = context; } }
這個時候可能你就有點暈了? AdapterDataSetObserver是什麼?它是如何運作的?那麼我就先來看看AdapterDataSetObserver吧。
AdapterDataSetObserver定義在ListView的父類AbsListView中,代碼如下 :
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver { @Override public void onChanged() { super.onChanged(); if (mFastScroller != null) { mFastScroller.onSectionsChanged(); } } @Override public void onInvalidated() { super.onInvalidated(); if (mFastScroller != null) { mFastScroller.onSectionsChanged(); } } }
它由繼承自AbsListView的父類AdapterView的AdapterDataSetObserver, 代碼如下 :
class AdapterDataSetObserver extends DataSetObserver { private Parcelable mInstanceState = null; // 上文有說道,調用Adapter的notifyDataSetChanged的時候會調用所有觀察者的onChanged方法,核心實現就在這裡 @Override public void onChanged() { mDataChanged = true; mOldItemCount = mItemCount; // 獲取Adapter中數據的數量 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(); // 重新布局ListView、GridView等AdapterView組件 requestLayout(); } // 代碼省略 public void clearSavedState() { mInstanceState = null; } }
到這裡我們就知道了,當ListView的數據發生變化時,調用Adapter的notifyDataSetChanged函數,這個函數又會調用DataSetObservable的notifyChanged函數,這個函數會調用所有觀察者 (AdapterDataSetObserver) 的onChanged方法。這就是一個觀察者模式!
最後我們再捋一捋,AdapterView中有一個內部類AdapterDataSetObserver,在ListView設置Adapter時會構建一個AdapterDataSetObserver,並且注冊到Adapter中,這個就是一個觀察者。而Adapter中包含一個數據集可觀察者DataSetObservable,在數據數量發生變更時開發者手動調用AdapternotifyDataSetChanged,而notifyDataSetChanged實際上會調用DataSetObservable的notifyChanged函數,該函數會遍歷所有觀察者的onChanged函數。在AdapterDataSetObserver的onChanged函數中會獲取Adapter中數據集的新數量,然後調用ListView的requestLayout()方法重新進行布局,更新用戶界面。
ListView主要運用了Adapter和觀察者模式使得可擴展性、靈活性非常強,而耦合度卻很低,這是我認為設計模式在Android源碼中優秀運用的典范。那麼為什麼Android架構師們會這麼設計ListView,它們如何達到低耦合、高靈活性呢?這個留給大家思考吧,如果有時間我再分享我的看法。
本文介紹Android開發過程中的一些基本常識,大多是一些流程、專業術語和解決問題的方法等。 軟件開發流程 一個完整的軟件開發流程離不開策劃、交互、視覺、軟件、測
一. 概述 Android系統將進程做得很友好的封裝,對於上層app開發者來說進程幾乎是透明的. 了解Android的朋友,一定知道Android四大組件,但對於
Android平台有三種網絡接口可以使用,他們分別是:java.net.*(標准Java接口)、Org.apache接口和Android.net.*(Androi
這裡逐條記錄下最容易遇到的 React native android 相關case 1.app啟動後,紅色界面,unable load jsbundle 解決辦法