第二期項目結束,繼續自己的部落格生涯。上周六給自己立過一個flag,對自己的承諾一定兌現,我就是注定成為大牛的偶豆扣。
Android開發中肯定少不了ListView,它總是配合BaseAdapter一起。每次我們更新資料的時候就會調用baseAdapter.notifyDataSetChanged()方法。實際其中就是用到了觀察者模式。那今天我們就來看看ListView中是如何使用觀察者模式的。
讓我們先看看BaseAdapter的源碼,不重要的代碼忽略。但是其中有個hasStableIds()方法預設傳回false,後面要用到。
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);
}
//通知所有觀察者資料改變
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
//通知所有觀察者資料更替
public void notifyDataSetInvalidated() {
mDataSetObservable.notifyInvalidated();
}
BaseAdapter裡有一個被觀察者DataSetObservable執行個體,他繼承自Observable,讓我們來看看它們怎麼寫的
public abstract class Observable<T> {
/**
* 一個泛型T的觀察者集合,
*/
protected final ArrayList<T> mObservers = new ArrayList<T>();
/**
* 添加觀察者到集合
*/
public void registerObserver(T observer) {
synchronized(mObservers) {//對象同步鎖
mObservers.add(observer);
}
}
/**
* 移除觀察者
*/
public void unregisterObserver(T observer) {
synchronized(mObservers) {
mObservers.remove(index);
}
}
/**
* 移除所有觀察者
*/
public void unregisterAll() {
synchronized(mObservers) {
mObservers.clear();
}
}
}
public class DataSetObservable extends Observable<DataSetObserver> {
/**
* 通知所有觀察者資料改變
*/
public void notifyChanged() {
synchronized(mObservers) {//mObservers繼承自Observable<T>
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
/**
* 通知所有觀察者資料更替
*/
public void notifyInvalidated() {
synchronized (mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onInvalidated();
}
}
}
}
典型的被觀察者的寫法,其實就是用一個集合來存儲觀察者,然後對這個集合進行操作。
listView.setAdapter(baseAdapter);//給listview設定擴充卡
接下來我們看看setAdapter的方法到底幹了什麼
@Override
public void setAdapter(ListAdapter adapter) {
//對觀察者模式不重要的代碼省略...
if (mAdapter != null) {
...
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
...
} else {...}
requestLayout();//重新布局
}
還記得BaseAdapter中的registerDataSetObserver方法嗎?接下來看看AdapterDataSetObserver這個觀察者是怎麼寫的
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
@Override
public void onChanged() {
super.onChanged();
if (mFastScroll != null) {
mFastScroll.onSectionsChanged();
}
}
@Override
public void onInvalidated() {
super.onInvalidated();
if (mFastScroll != null) {
mFastScroll.onSectionsChanged();
}
}
}
AdapterDataSetObserver這個類隻是單純的設定了一下ListView的快速滾動,那我們去他的父類看看。它是AdapterView的一個内部類。
class AdapterDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
mDataChanged = true;//改變狀态
mOldItemCount = mItemCount;//記錄下上次的數量
mItemCount = getAdapter().getCount();//記錄下這次的數量
//還記得hasStableIds預設傳回什麼嗎?
if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
&& mOldItemCount == 0 && mItemCount > 0) {
....
} else {
rememberSyncState();//記住各種狀态和資料(頂部偏移量等)
}
checkFocus();//檢測焦點
requestLayout();//view的方法,重新布局
}
@Override
public void onInvalidated() {
...//重置了所有的位置狀态
}
}
源碼就看到這裡,基本上邏輯已經搞清楚了。setAdapter的時候會注冊一個觀察者。notifyDataSetChanged的時候會通知觀測者,可以讓AdapterView調用相應的邏輯,最後重新整理資料。