一:PagerAdapter#notifyDataSetChanged调用过程
PagerAdapter#notifyDataSetChanged方法源码注:这里会通过mViewPagerObserver.onchanged()回调通知viewpager
ViewPager#setadapter方法源码注:前面调用adapter的回调通知 是在Viewpager#setadapter方法时通过this.mAdapter.setViewPagerObserver(this.mObserver);给adapter注册的回调
ViewPager#PagerObserver类注:PagerObserver是Viewpager的一个内部类,所以notifyDataSetChanged的时候最终会调用ViewPager#dataSetChanged方法
ViewPager#dataSetChanged部分源码注:ViewPager#dataSetChanged 才是 adapter数据刷新的处理,要先找到这里才能开始分析。
Viewpager静态内部类Iteminfo Viewpager#setCurrentItemInternal Viewpager#populate部分源码二:fragmentStateAdapter 数据修改:
1.增:
方法:viewpager#dataSetChanged:
1. boolean needPopulate = this.mItems.size() <this.mOffscreenPageLimit *2 +1 &&this.mItems.size() < adapterCount ;(增的情况下 计算结果都是ture)
2.newPos = - 1(viewpager内部默认-1,用户可修改)
3.if(newPos == -1) 什么事情都不做
4.if(newPos == -2) 会对viewpager中的mItems进行remove然后 mAdapter.destroyItem 同时更新viewpager当前页(增的情况下,不变)。随后needPopulate =true
5.if(needPopulate){
this.setCurrentItemInternal(newCurrItem,false,true);
this.requestLayout();
}
6.setCurrentItemInternal方法内部根据mFirstLayout判断是否执行this.populate(item);(mFirstLayout = false)
7.populate会根据当前的页码数和用户设置的mOffscreenPageLimit和ItemInfo中的widthFactor计算需不需要去执行Viewpager#addNewItem();
8.addNewItem 会去执行adapter.instantiateItem()方法;
结论1:if(newPos == -2) 会让viewpager清除ArrayList<ViewPager.ItemInfo> mItems 的内容。同时this.mAdapter.destroyItem(this, ii.position, ii.object);
结论2(仅仅只是增长adapter集合):notifyDataSetChanged 必定会调用populate方法,假如mItems是空的(newpos == -2),必定会去addnewitem同时this.mAdapter.instantiateItem(this, position);假如newpos == -1的情况,会根据当前页和viewpager偏移值去判定需不需要调用addnewitem。
结论3:仅仅只是增长adapter集合viewpager不会有问题;
2.改(不增加和减少adapter中数据的长度):
1. boolean needPopulate = this.mItems.size() <this.mOffscreenPageLimit *2 +1 &&this.mItems.size() < adapterCount ;(改的情况下 mOffscreenPageLimit为1的情况下 adapter长度为1和2的时候needPopulate为false ,3的时候当前页在中间的时候为false,其他为true)
2.newPos = - 1(viewpager内部默认-1,用户可修改)
3.if(newPos == -1) 什么事情都不做
4.if(newPos == -2) 会对viewpager中的mItems进行remove然后 mAdapter.destroyItem 同时更新viewpager当前页(改的情况下,不变)。随后needPopulate =true
5.if(needPopulate){
this.setCurrentItemInternal(newCurrItem,false,true);
this.requestLayout();
}
6.根据mFirstLayout判断是否执行this.populate(item);(mFirstLayout = false)
总结:所以这里有3种情况:
1. needPopulate= false && newPos == -1 -------> (表现为ui不更改)
2. needPopulate= true && newPos == -1 -------> (表现为ui不更改)
3. needPopulate= true && newPos == -2 -------> (表现为ui根据adapter提供的实例修改)
情况1:不需要调用
情况2:调用了populate,但是需要的iteminfo都存在所以不会调用addnewitem,导致如果集合中相同位置的引用改变了。使用的还是mItems缓存的旧的对象,假如mitems中的每一个对象都有remove的机会那么视图在拖动中总有机会去更新到最新的。
情况3:清空了mItems,导致每一项重新开始调用addnewitem和this.mAdapter.instantiateItem(this, position)。
2.删:
和改一样有3种情况
1. needPopulate= false && newPos == -1 -------> ui无修改
2. needPopulate= true && newPos == -1 -------> ui展现正确的当前页
3. needPopulate= true && newPos == -2 ------->(表现为ui根据adapter提供的实例修改)
注:1.其中情况2假如是从不正确的当前页修改为正确的当前页,他还是可以拖动到后 一页应为 mItems 并没有清除之前的iteminfo所以在ontouch#case2的performdrag中rightBound 计算 还是按照之前的方法计算然后调用scrollTo 去滚动。但是ontouch#case1:this.setCurrentItemInternal(nextPage,true,true, initialVelocity)------>else if (item >=this.mAdapter.getCount()) {
item =this.mAdapter.getCount() -1;
}和 this.scrollToItem(item, smoothScroll, velocity, dispatchSelected);
又给他设置到正确的位置了,然后ui就是 可以拖到最后一页但是就是翻不过去;
2.和情况2类似,情况一假如翻到最后一页,然后调用notifyDataSetChanged没有反应,但是在你收触摸到屏幕,不管是什么方向的去触发performdarg 他最后都会返回到正确的最后一页。
讨论:needPopulate 值在删情况下变动:
mOffscreenPageLimit 为1:
adapter 的数据长度改动 当前页 (从1开始) needPopulate值
1-----0 1 false
2-----1 1 false
2-----1 2 false
3-----2 1 false
3-----2 2 false
3-----2 3 false
4-----3 1 true
4-----3 2 false
4-----3 3 false
4-----3 4 true
所以得出 也不是在删数据的时候都会去设置正确的当前页面。比如在3-2,和4-3的ui变动是不一样的,这是由needPopulate值决定的。
三:记录完了。over
网友评论