registerDataSetObserver:浅析Andorid ListView和Adapter

最近由于遇到将内容分部绑定到ListView里的需求,追踪源码之后对ListView和Adapter有了点肤浅的认识,在此与大家分享。

这里用到了观察者模式,在ListView的setAdapter里注册一个AdapterDataSetObserver观察者。

public void setAdapter(ListAdapter adapter) {
........
mDataSetObserver = new AdapterDataSetObserver();//AdapterDataSetObserver是ListView的基类AdapterView的内部类
mAdapter.registerDataSetObserver(mDataSetObserver);//注册一个观察者
.........
requestLayout();//更新视图
}

ListAdapter是一接口,BaseAdapter继承了它

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    private final DataSetObservable mDataSetObservable = new DataSetObservable();
 
    public boolean hasStableIds() {
        return false;
    }
     
    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();
    }
 
    /**
     * Notifies the attached observers that the underlying data is no longer valid
     * or available. Once invoked this adapter is no longer valid and should
     * not report further data set changes.
     */
    public void notifyDataSetInvalidated() {
        mDataSetObservable.notifyInvalidated();
    }
 
    public boolean areAllItemsEnabled() {
        return true;
    }
 
    public boolean isEnabled(int position) {
        return true;
    }
 
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return getView(position, convertView, parent);
    }
 
    public int getItemViewType(int position) {
        return 0;
    }
 
    public int getViewTypeCount() {
        return 1;
    }
     
    public boolean isEmpty() {
        return getCount() == 0;
    }
}

DataSetObservable定义如下:

public class DataSetObservable extends Observable<DataSetObserver> {
    public void notifyChanged() {//通知每个观察者数据已变化
        synchronized(mObservers) {
            for (DataSetObserver observer : mObservers) {
                observer.onChanged();
            }
        }
    }
 
    public void notifyInvalidated() {
        synchronized (mObservers) {
            for (DataSetObserver observer : mObservers) {
                observer.onInvalidated();
            }
        }
    }
}

ListView里注册的观察者是AdapterDataSetObserver对象,其定义如下:

class AdapterDataSetObserver extends DataSetObserver {
 
        private Parcelable mInstanceState = null;
 
        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            mItemCount = getAdapter().getCount();//Adapter现有元素个数
 
            if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                    && mOldItemCount == 0 && mItemCount > 0) {
                AdapterView.this.onRestoreInstanceState(mInstanceState);
                mInstanceState = null;
            } else {
                rememberSyncState();
            }
            checkFocus();
            requestLayout();//更新视图
        }
.................
}

AdapterDataSetObserver里的具体实现我没弄清楚,但感觉是在这里更新了ListView显示的数据,ListView里是怎样更新的没弄清楚,希望哪位高手知道的告诉我。

但是如果只在ListView里显示Adapter的部分数据,该怎么弄呢,可继承BaseAdapter,实现BaseAdapter里未实现的如下方法:

getCount()、getItem(int position)、getItemId(int position)、getView(int position, View convertView, ViewGroup parent)。

只需在getCount里返回想要的大小就行了。

个人见解,错误之处请高手指正。