ListView更新介面的原理
阿新 • • 發佈:2018-11-05
ListView是我們經常使用的一個控制元件。那麼,當我們刪除或者新增ListView中的一個item時,介面是如何更新的呢?為了及時更新介面,ListView使用了觀察者模式,在我們資料來源發生改變時,我們呼叫了notifyDatasetchange方法,介面發生改變。下面,我們一起看看notifyDataSetChanged的原始碼實現。
既然,更新介面需要呼叫notifyDataSetChange方法。那我們就首先看下這個方法的主要程式碼。
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(); } }
在該方法中實現了對觀察者的新增和刪除,以及通知觀察者做出變化的方法。接下來在看看notifyChange方法。
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 (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } } }
呼叫了這個方法後,會倒敘遍歷觀察者集合裡面的觀察者做出響應。
當我們呼叫Adapter的setAdapter方法時候,會建立觀察者並新增進觀察者集合。
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(); }
在該方法中,建立了觀察者並註冊進被觀察者集合中。
AdapterDataSetObserver繼承自AdapterView中的AdapterDataSetObserver(繼承自AbsListView中的DataSetObserver),佈局改變後呼叫onChange方法中的requestLayout方法重新佈局。
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();
}
}
}
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();
}
public void clearSavedState() {
mInstanceState = null;
}
}