[Android]中ViewPager+PagerAdapter源碼分析

 本文主要解決應用ViewPager和PagerAdapter時,調用ViewPager中的getAdapter()方法,獲取Adapter對象之後調用notifyDataSetChanged()方法如何達到更新數據的目的。先不考慮FragmentStatePagerAdapter和FragmentPagerAdapter這兩個基於PagerAdpter的衍生類


  1. 首先一張圖來看下ViewPager和PagerAdapter裏面會涉及到的東西
    這裏寫圖片描述
  2. 主要類的簡單介紹

    • ViewPager
      這是一個用於翻頁展示的類,裏面包含了用於展示的相關信息
static class ItemInfo {
        Object object;//每次用於展示的對象
        int position;//每個Item的在ViewPager中的位置
        boolean scrolling;//是否在滾動
        float widthFactor;//表示加載的頁面佔ViewPager所佔的比例[0~1](默認返回1)
        float offset;//偏移量
    }
private class PagerObserver extends DataSetObserver {
        @Override
        public void onChanged() {
            dataSetChanged();
        }
        @Override
        public void onInvalidated() {
            dataSetChanged();
        }
    }

這是一個對數據集(DataSet)進行觀察的類,當數據集改變時,會調用他的onChanged()或者onInvalidated()方法。這個對象需要在PagerAdapter()中的被觀察者(DataSetObservable)中進行註冊

對於setAdapter()方法:

public void setAdapter(PagerAdapter adapter) {
        if (mAdapter != null) {
            mAdapter.unregisterDataSetObserver(mObserver);
            mAdapter.startUpdate(this);//註銷觀察者
            for (int i = 0; i < mItems.size(); i++) {
                final ItemInfo ii = mItems.get(i);
                mAdapter.destroyItem(this, ii.position, ii.object);
                //使得在ViewPager中調用PagerAdapter裏面的方法成爲了可能
            }
            mAdapter.finishUpdate(this);
            mItems.clear();
            removeNonDecorViews();
            mCurItem = 0;
            scrollTo(0, 0);
        }
//省略....
        if (mAdapter != null) {
            if (mObserver == null) {
                mObserver = new PagerObserver();
            }
            mAdapter.registerDataSetObserver(mObserver);//註冊觀察者
    //以下省略...
        }
        //以下省略...
    }

setAdapter()方法建立了ViewPager和PagerAdapter的聯繫,通過註冊觀察者,讓ViewPager能夠接收到數據變化時,重新加載數據的請求

  • PagerAdapter類
    主要作用是爲了給ViewPager提供需要展示的內容,這是一個內容生成器。需要說明的是這是一個抽象類,需要在繼承時實現裏面的
    • instantiateItem():在這裏面初始化Item的內容
    • destroyItem() : 銷燬Item
    • getCount() : 返回Item的數目
    • isViewFromObject()。標識一個視圖是否和給定的Key對象相關[1]

3 . 當數據變化時的流程
首先在activity中會調用 ViewPager.getAdapter().notifyDataSetChanged()方法,通知數據發生改變

public void notifyDataSetChanged() {
        mObservable.notifyChanged();
        //然後去調用DataSetObservable類中的方法
    }

DataSetObservable類中:

public void notifyChanged() {
        synchronized(mObservers) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged(); 
                //通知所有觀察者數據發生變化,其中包括已經在setAdapter()時註冊的PagerObserver
            }
        }
    }

在ViewPager內部類PagerObserver中接收到通知(這是觀察者模式的應用)並調用其中的onChanged()方法裏面的dataSetChanged()方法,我們看到這個方法的內容:

void dataSetChanged() {
        // This method only gets called if our observer is attached, so mAdapter is non-null.
        for (int i = 0; i < mItems.size(); i++) {
            final ItemInfo ii = mItems.get(i);
            final int newPos = mAdapter.getItemPosition(ii.object);

            if (newPos == PagerAdapter.POSITION_UNCHANGED) {
                continue;
            }

            if (newPos == PagerAdapter.POSITION_NONE) {
                mItems.remove(i);
                i--;
                if (!isUpdating) {
                    mAdapter.startUpdate(this);
                    isUpdating = true;               
                }
                mAdapter.destroyItem(this, ii.position, ii.object);
                needPopulate = true;
                //這裏是對PagerAdapter.getItemPosition()方法的返回值進行判斷:
                //POSITION_NONE時進行數據更新,
                //POSITION_UNCHANGED時,標識符 needPopulate=false 不更新數據    
                .
                .
                .
        if (needPopulate) {
            .
            .
            .
            setCurrentItemInternal(newCurrItem, false, true);
            //這裏會去調用populate()方法(這個方法的主要作用就是加載和渲染頁面)
            //重新做了加載數據的操作
            requestLayout();
        }
    }

到此數據更新完成。

4 .參考:
a.http://www.cnblogs.com/dancefire/archive/2013/01/02/why-notifydatasetchanged-does-not-work.html
b.http://blog.csdn.net/u011494050/article/details/45366763
c.http://www.jianshu.com/p/85afaf9e8f6e
d.http://blog.csdn.net/u011494050/article/details/45366763
[1].http://blog.csdn.net/dmk877/article/details/50060745

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章