編輯:關於Android編程
[java]
/*
* 觀察者模式
* 定義對象間的一種一個(Subject)對多(Observer)的依賴關系,當一個對象的狀態發送改變時,所以依賴於它的
* 對象都得到通知並被自動更新
*
* 當然,MVC只是Observer模式的一個實例。Observer模式要解決的問題為:
* 建立一個一(Subject)對多(Observer)的依賴關系,並且做到當“一”變化的時候,
* 依賴這個“一”的多也能夠同步改變。最常見的一個例子就是:對同一組數據進行統計分析時候,
* 我們希望能夠提供多種形式的表示(例如以表格進行統計顯示、柱狀圖統計顯示、百分比統計顯示等)。
* 這些表示都依賴於同一組數據,我們當然需要當數據改變的時候,所有的統計的顯示都能夠同時改變。
* Observer模式就是解決了這一個問題。
*
* 適用性:
* 1. 當一個抽象模型有兩個方面,其中一個方面依賴於另一方面
* 將這兩者封裝成獨立的對象中以使它們可以各自獨立的改變和服用
*
* 2. 當對一個對象的改變需要同時改變其他對象,而不知道具體有多少對象有待改變
*
* 3. 當一個對象必須通知其它對象,而它又不能假定其它對象是誰
*
* 參與者:
* 1. Subject(目標)
* 目標知道它的觀察者,可以有任意多個觀察者觀察同一個目標
* 提供注冊和刪除觀察者對象的接口
*
* 2. Observer(觀察者)
* 為那些在目標發生改變時需獲得通知的對象定義個更新的接口
*
* 3. ConcreteSubject(具體目標)
* 將有關狀態存入各ConcreteObserver對象
* 當它的狀態發送改變時,向它的各個觀察者發出通知
*
* 4. ConcreteObserver(具體觀察者)
* 維護一個指向ConcreteObserver對象的引用
* 存儲有關狀態,這些狀態應與目標的狀態保持一致
* 實現Observer的更新接口是自身狀態與目標的狀態保持一致
*
*
* */
有空我將把UML圖補上。
下面看看Android使用到的觀察者模式.
觀察者(DataSetObserver),目標(Observable<T>),具體目標(DataSetObserverable)
Observer(觀察者),DataSetObserver抽象2個方法,一個是觀察數據改變的方法,一個是觀察數據變成無效(或者不可用)時的方法。
源碼路徑:framework/base/core/java/android/database/DataSetObserver.java
[java]
package android.database;
/**
* Receives call backs when a data set has been changed, or made invalid. The typically data sets
* that are observed are {@link Cursor}s or {@link android.widget.Adapter}s.
* DataSetObserver must be implemented by objects which are added to a DataSetObservable.
*/
public abstract class DataSetObserver {
/**
* This method is called when the entire data set has changed,
* most likely through a call to {@link Cursor#requery()} on a {@link Cursor}.
*/
public void onChanged() {
// Do nothing
}
/**
* This method is called when the entire data becomes invalid,
* most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a
* {@link Cursor}.
*/
public void onInvalidated() {
// Do nothing
}
}
Subject(目標),Observable<T>是一個泛型的抽象類,主要功能是注冊和撤銷observer。
源碼路徑:framework/base/core/java/android/database/Observable.java
[java]
package android.database;
import java.util.ArrayList;
/**
* Provides methods for (un)registering arbitrary observers in an ArrayList.
*/
public abstract class Observable<T> {
/**
* The list of observers. An observer can be in the list at most
* once and will never be null.
*/
protected final ArrayList<T> mObservers = new ArrayList<T>();
/**
* Adds an observer to the list. The observer cannot be null and it must not already
* be registered.
* @param observer the observer to register
* @throws IllegalArgumentException the observer is null
* @throws IllegalStateException the observer is already registered
*/
public void registerObserver(T observer) {
if (observer == null) {
throw new IllegalArgumentException("The observer is null.");
}
synchronized(mObservers) {
if (mObservers.contains(observer)) {
throw new IllegalStateException("Observer " + observer + " is already registered.");
}
mObservers.add(observer);
}
}
/**
* Removes a previously registered observer. The observer must not be null and it
* must already have been registered.
* @param observer the observer to unregister
* @throws IllegalArgumentException the observer is null
* @throws IllegalStateException the observer is not yet registered
*/
public void unregisterObserver(T observer) {
if (observer == null) {
throw new IllegalArgumentException("The observer is null.");
}
synchronized(mObservers) {
int index = mObservers.indexOf(observer);
if (index == -1) {
throw new IllegalStateException("Observer " + observer + " was not registered.");
}
mObservers.remove(index);
}
}
/**
* Remove all registered observer
*/
public void unregisterAll() {
synchronized(mObservers) {
mObservers.clear();
}
}
}
ConcreateSubject(具體目標),實現的方法同Oberver一樣,只不過它是通知ArrayList<Observer>下的每個Oberver去執行各自的action。
源碼路徑:framework/base/core/java/android/database/DataSetObservable.java
[java]
package android.database;
/**
* 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) {
// since onChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
/**
* Invokes onInvalidated on each observer. Called when the data set being monitored
* has changed such that it is no longer valid.
*/
public void notifyInvalidated() {
synchronized (mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onInvalidated();
}
}
}
}
ConcreateObserver(具體觀察者),具體觀察者的任務是實實在在執行action的類,一般由開發者根據實際情況,自己實現。android也有實現的例子
源碼路徑:
framework/base/core/java/android/widget/AbsListView.java
[java]
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();
}
}
}
framework/base/core/java/android/widget/AdapterView.java
[java]
class AdapterDataSetObserver extends DataSetObserver {
private Parcelable mInstanceState = null;
@Override
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = getAdapter().getCount();
if (DBG) {
Xlog.d(TAG, "AdapterView onChanged: mOldItemCount = " + mOldItemCount
+ ",mItemCount = " + mItemCount + ",getAdapter() = " + getAdapter()
+ ",AdapterView = " + AdapterView.this, new Throwable("onChanged"));
}
// 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();
requestLayout();
}
@Override
public void onInvalidated() {
mDataChanged = true;
if (DBG) {
Xlog.d(TAG, "AdapterView onInvalidated: mOldItemCount = " + mOldItemCount
+ ",mItemCount = " + mItemCount + ",getAdapter() = " + getAdapter()
+ ",AdapterView = " + AdapterView.this, new Throwable("onInvalidated"));
}
if (AdapterView.this.getAdapter().hasStableIds()) {
// Remember the current state for the case where our hosting activity is being
// stopped and later restarted
mInstanceState = AdapterView.this.onSaveInstanceState();
}
// Data is invalid so we should reset our state
mOldItemCount = mItemCount;
mItemCount = 0;
mSelectedPosition = INVALID_POSITION;
mSelectedRowId = INVALID_ROW_ID;
mNextSelectedPosition = INVALID_POSITION;
mNextSelectedRowId = INVALID_ROW_ID;
mNeedSync = false;
checkFocus();
requestLayout();
}
public void clearSavedState() {
mInstanceState = null;
}
}
實例:
型運用是大家熟悉的BaseAdapter,BaseAdapter關聯了一個DataSetObservable對象,並實現registerDataSetObserver和unregisterDataSetObserver兩個方法實現注冊和撤銷Observer,方法notifyDataSetChanged間接調用Observer的實現者的onChange()方法,以達到通知數據改變的作用。使用ListView和BaseAdapter組合時,當BaseAdapter的item改變時,我們經常會調用notifyDataSetChanged(),通知Listview刷新。
但是,但是,但是,我們從來沒有調用BaseAdapter的registerDataSetObserver(DataSetObserver observer)注冊Observer,那麼Listview如何接收到通知,並執行刷新動作呢?
我們來看看ListView做了什麼
[java]
/**
* Sets the data behind this ListView.
*
* The adapter passed to this method may be wrapped by a {@link WrapperListAdapter},
* depending on the ListView features currently in use. For instance, adding
* headers and/or footers will cause the adapter to be wrapped.
*
* @param adapter The ListAdapter which is responsible for maintaining the
* data backing this list and for producing a view to represent an
* item in that data set.
*
* @see #getAdapter()
*/
@Override
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
resetList();
mRecycler.clear();
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
mOldSelectedPosition = INVALID_POSITION;
mOldSelectedRowId = INVALID_ROW_ID;
// AbsListView#setAdapter will update choice mode states.
super.setAdapter(adapter);
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();
checkFocus();
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
int position;
if (mStackFromBottom) {
position = lookForSelectablePosition(mItemCount - 1, false);
} else {
position = lookForSelectablePosition(0, true);
}
setSelectedPositionInt(position);
setNextSelectedPositionInt(position);
if (mItemCount == 0) {
// Nothing selected
checkSelectionChanged();
}
} else {
mAreAllItemsSelectable = true;
checkFocus();
// Nothing selected
checkSelectionChanged();
}
requestLayout();
}
注意下面3行
[java]
mAdapter = adapter;
[java] www.2cto.com
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
當我們setAdapter(ListAdapter adapter)時,BaseAdapter同時注冊了AdapterDataSetObserver(),至於AdapterDataSetObserver是如何通知Listvew和每個子item刷新(invalidate)的,這裡涉及到的內容已經超出文章的范圍,具體請查看源碼。
其實,Android用到DataSetObserver的地方很多,Cursor,WebView,Adapter,...非常之多。
作者:fangchongbory
Android通訊錄的制作有很多種方式,網上大部分也都有了,但是用數據庫制作通訊錄的卻少之又少,這裡我就制作一個簡單的app供大家學習先看一下效果圖,在下面有提供項目源碼
今天繼續AndroidUI組件的講解(寫博客只是為了鞏固與繼續學習知識----工欲善其事,必先利其器!) 下面是主Activity的源碼,裡面附含知識點的講解,在前面的博
360奇酷手機出自酷派和360合資公司,奇酷手機以及酷派手機都屬於安卓系統,那麼奇酷手機、酷派手機怎麼刷機呢?手機有毛病可以嘗試恢復手機出廠設置,操作方法如
摘要:剛一開始接觸Chromium on Android時,就很好奇Chromium的主消息循環是怎麼整合到Android應用程序中的。對於Android程序來說,一旦啟