[Android]中ViewPager+PagerAdapter源码分析

本文详细解析了使用ViewPager和PagerAdapter时,如何通过notifyDataSetChanged()方法更新数据。从ViewPager和PagerAdapter的工作原理入手,介绍了数据变化时的具体流程,包括观察者模式的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 本文主要解决应用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.youkuaiyun.com/u011494050/article/details/45366763
c.http://www.jianshu.com/p/85afaf9e8f6e
d.http://blog.youkuaiyun.com/u011494050/article/details/45366763
[1].http://blog.youkuaiyun.com/dmk877/article/details/50060745

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值