編輯:Android編程入門
生活中我們常認定某些人很有才,但什麼是有才呢?明朝的王守仁曾這樣解釋:才,是所謂天理,應用到物上,便成了才。凡事凡物,只要掌握了所謂科學的方法,並能靈活運用,那麼你也可以成為一個有才的人。
觀察者模式是軟件設計都會運用到的一種模式,無論何種預言,由於本人是android猿類,所以本篇僅探討android中的觀察者模式,為了詳致地闡述這一模式,本文分為三個部分:概念、簡單實現、android中listview的具體實現。看完這三部分,相信您自己也能夠駕輕就熟地在自己的軟件中編寫觀察者模式了。
每逢花晨月夕,便有絲竹管弦之興,美文就要來襲了:)
一、概念

二、簡單實現
依照圖示,上代碼:首先是observer的接口類
/**
* Created by 笑飛 on 2016/4/28.
* 觀察者,需要應用觀察者模式時要實現此接口
*/
public interface Observer {
void onUpdate();
}
其次是observer的實現類
/**
* Created by 笑飛 on 2016/4/28.
*/
public class ConcreteObserver implements Observer {
private String myOnlyAttr;
private int changeCount;
/*刷新自己*/
@Override
public void onUpdate() {
myOnlyAttr = "通知Observer刷新了:"+(changeCount++)+"次";
}
public String getMyOnlyAttr() {
return myOnlyAttr;
}
}
其次是subject的祖宗類
/**
* Created by 笑飛 on 2016/4/28.
* 發送者,需要應用觀察者模式時的被觀察者要繼承此類
*/
public abstract class Subject {
/*將一個被觀察者對象和多個觀察者對象綁定起來*/
protected List<Observer> observers = new ArrayList<>();
/*添加觀察者,我們可能需要各種各樣的觀察者*/
public void attachObserver(Observer observer){
if (null ==observer){
throw new NullPointerException();
}
if (!observers.contains(observer)){
observers.add(observer);
}
}
public void detachObserver(Observer observer){
if (null ==observer){
throw new NullPointerException();
}
if (observers.contains(observer)){
observers.remove(observer);
}
}
public abstract void notifyObserverUpdate();
}
其次是subject的實現類:
/**
* Created by 笑飛 on 2016/4/28.
* 實現了刷新方法
*/
public class ConcreteSubject extends Subject {
@Override
public void notifyObserverUpdate() {
for (Observer observer :observers){
observer.onUpdate();
}
}
}
然後是activity的測試部分
public class MainActivity extends AppCompatActivity {
private ConcreteSubject subject;
private TextView textView;
ConcreteObserver observer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
observer = new ConcreteObserver();
subject = new ConcreteSubject();
/*綁定觀察者*/
subject.attachObserver(observer);
}
public void update(View v){
/*通知觀察者刷新*/
subject.notifyObserverUpdate();
textView.setText(observer.getMyOnlyAttr());
}
}
在開始第三部分之前,我們要注意,如果把上面的observer換成listview,把subject換成adapter,是不是我們經常看到和用到的listview的用法?其實 listview內置了observer,而adpter中內置了subject,換言之,listview和adapter其實就是觀察者與被觀察者的“形象代言人”。
好了,接下啦讓我們以android中的經典ArrayAdapter來開始第三部分的分析吧!
三、android中listview的具體實現
public void setAdapter(ListAdapter adapter) {
if (null != mAdapter) {
mAdapter.unregisterDataSetObserver(mDataSetObserver); // 關鍵的成員變量,繼承自AbsListView,等下去看看AbsListView關於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;
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();
checkFocus();
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver); // 在這裡進行注冊,注冊為發送者adapter的觀察者
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();
}
if (mChoiceMode != CHOICE_MODE_NONE &&
mAdapter.hasStableIds() &&
mCheckedIdStates == null) {
mCheckedIdStates = new LongSparseArray<Boolean>();
}
} else {
mAreAllItemsSelectable = true;
checkFocus();
// Nothing selected
checkSelectionChanged();
}
if (mCheckStates != null) {
mCheckStates.clear();
}
if (mCheckedIdStates != null) {
mCheckedIdStates.clear();
}
requestLayout();
}
}
mDataSetObserver這個觀察者在AbsListView中:
AdapterDataSetObserver mDataSetObserver; // mDataSetObserver就是在這裡定義的。那我們再看看AdapterDataSetObserver是什麼類型的數據,看看當數據發生變化的時候,該類會進行什麼樣的動作。
接下來去AdapterView中,發現AdapterDataSetObserver是其一個內部類:
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();
requestLayout(); // 這裡是關鍵:這就是為什麼數據發生了變化,視圖可以隨之變換的原因,因為它會調用框架,來進行重新繪制。最終調用的代碼看緊接著的代碼
}
@Override
public void onInvalidated() {
mDataChanged = true;
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;
checkSelectionChanged();
checkFocus();
requestLayout();
}
public void clearSavedState() {
mInstanceState = null;
}
}
在ArrayAdapter中:
@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged(); // 關鍵代碼,這個notifyDataSetChanged()是從父類BaseAdapter繼承過來的,所以看看在父類中它干了些什麼
mNotifyOnChange = true;
}
然後在BaseAdapter中:
private final DataSetObservable mDataSetObservable = new DataSetObservable();
//這對方法用來注冊或注銷從屬ArrayAdapter的觀察者,從此以後,adapter就成了發送者(Observable)的代理人 public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } public void unregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); }
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged(); // 關鍵代碼:說明調的是成員變量mDataSetObservable的方法,所以進入DataSetObservable看看具體是如何操作的
}
接下來看發送者和發送者的祖宗,是不是很熟悉了?請自行與第二部分的發送者對應:
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) {
for (DataSetObserver observer : mObservers) { // 這裡的mObservers是哪來的呢?繼續追蹤,但首先可以判斷是來自Observable<DataSetObserver>的。進入看看
observer.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 (DataSetObserver observer : mObservers) {
observer.onInvalidated();
}
}
}
}
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>();
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);
}
}
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);
}
}
public void unregisterAll() {
synchronized(mObservers) {
mObservers.clear();
}
}
}
總結:觀察者模式看起來很高大上,其實說白了就是一個類維護了另一個類的一個集合,並通過這個集合綁定解綁或調用另一個類的方法,只不過,在設計底層框架時候,利用了多態的特性抽象出了接口和抽象類,以便適用於各種場合。其實在做終端頁面時候完全用不到,因為多態只能增加運行時開銷。然而,設置一個龐大系統時候,這種設計模式在面向對象的編程語言,可謂不能不用的手段了。
寫一個Android輸入法02——候選窗、轉換
上一篇上一篇介紹了完成Android輸入法的最小化步驟,它只能將按鍵對應的字符上屏。一般的東亞語言都有一個轉換的過程,比如漢語輸入拼音,需要由拼音轉成漢字再上屏。本文將在
Android開發學習之路-Android Studio真神器!
放假之後電腦配置升級就開始用Android Studio(下面簡稱AS)了,那個酸爽真的不是一般的啊,這裡開一篇博客來記錄下AS裡面各種酷炫的功能,有更好玩的,大家不要吝
Android自定義SurfaceView實現雪花效果
實現雪花的效果其實也可以通過自定義View的方式來實現的(SurfaceView也是繼承自View的),而且操作上也相對簡單一些,當然也有一些
android開發環境以及genymotion虛擬機配合HBuilder測試(自總結)
一、安裝android-studiohttps://github.com/inferjay/AndroidDevToolsbundle版集成環境win7jdk(JAVA環