当前位置:网站首页>Viewpager pageradapter notifydatasetchanged invalid problem
Viewpager pageradapter notifydatasetchanged invalid problem
2022-07-05 09:36:00 【Black Mountain demon 2018】
As we all know , Whether we are using RecyclerView still ListView when , After updating the data source, it will call adapter Of notifyDataSetChanged() Method to update the view . and PagerAdapter Namely ViewPager The use of adapter, But in practice , It is found that updating the data source does not necessarily update the view .
Let's take a look at Google's right PagerAdapter This method of notifyDataSetChanged() The definition of
Personally, I don't think the definition of Google's method is a good explanation for the problems I encounter in my work , So try the source code ...
/**
* This method should be called by the application if the data backing this adapter has changed
* and associated views should update.
*/
public void notifyDataSetChanged() {
synchronized (this) {
if (mViewPagerObserver != null) {
mViewPagerObserver.onChanged();
}
}
mObservable.notifyChanged();
}
At first glance, it is the observer mode , Here we only focus on mViewPagerObserver, See where it is assigned .
void setViewPagerObserver(DataSetObserver observer) {
synchronized (this) {
mViewPagerObserver = observer;
}
}
Let's see where this method is called .
/** * Set a PagerAdapter that will supply views for this pager as needed. * * @param adapter Adapter to use */ public void setAdapter(PagerAdapter adapter) { if (mAdapter != null) { mAdapter.setViewPagerObserver(null); mAdapter.startUpdate(this); for (int i = 0; i < mItems.size(); i++) { final ItemInfo ii = mItems.get(i); mAdapter.destroyItem(this, ii.position, ii.object); } mAdapter.finishUpdate(this); mItems.clear(); removeNonDecorViews(); mCurItem = 0; scrollTo(0, 0); } final PagerAdapter oldAdapter = mAdapter; mAdapter = adapter; mExpectedAdapterCount = 0; if (mAdapter != null) { if (mObserver == null) { mObserver = new PagerObserver(); } mAdapter.setViewPagerObserver(mObserver); mPopulatePending = false; final boolean wasFirstLayout = mFirstLayout; mFirstLayout = true; mExpectedAdapterCount = mAdapter.getCount(); if (mRestoredCurItem >= 0) { mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); setCurrentItemInternal(mRestoredCurItem, false, true); mRestoredCurItem = -1; mRestoredAdapterState = null; mRestoredClassLoader = null; } else if (!wasFirstLayout) { populate(); } else { requestLayout(); } } // Dispatch the change to any listeners if (mAdapterChangeListeners != null && !mAdapterChangeListeners.isEmpty()) { for (int i = 0, count = mAdapterChangeListeners.size(); i < count; i++) { mAdapterChangeListeners.get(i).onAdapterChanged(this, oldAdapter, adapter); } } }
In the above code, it is seen in setAdapter Assign values in this method , And see mObserver = new PagerObserver();mObserver This object is also created in this method , I want to see others PagerObserver This class , Is a private inner class .
private class PagerObserver extends DataSetObserver { PagerObserver() { } @Override public void onChanged() { dataSetChanged(); } @Override public void onInvalidated() { dataSetChanged(); } }
Now it's clear ,notifyDataSetChanged() In the method mViewPagerObserver.onChanged() Execution is dataSetChanged() Method , Let's see dataSetChanged() This method .
void dataSetChanged() {
// This method only gets called if our observer is attached, so mAdapter is non-null.
final int adapterCount = mAdapter.getCount();
mExpectedAdapterCount = adapterCount;
boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1
&& mItems.size() < adapterCount;
int newCurrItem = mCurItem;
boolean isUpdating = false;
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;
if (mCurItem == ii.position) {
// Keep the current item in the valid range
newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1));
needPopulate = true;
}
continue;
}
if (ii.position != newPos) {
if (ii.position == mCurItem) {
// Our current item changed position. Follow it.
newCurrItem = newPos;
}
ii.position = newPos;
needPopulate = true;
}
}
if (isUpdating) {
mAdapter.finishUpdate(this);
}
Collections.sort(mItems, COMPARATOR);
if (needPopulate) {
// Reset our known page widths; populate will recompute them.
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (!lp.isDecor) {
lp.widthFactor = 0.f;
}
}
setCurrentItemInternal(newCurrItem, false, true);
requestLayout();
}
}
See the red mark , I want to see others getItemPosition() This method ,
/** * Called when the host view is attempting to determine if an item's position * has changed. Returns {@link #POSITION_UNCHANGED} if the position of the given * item has not changed or {@link #POSITION_NONE} if the item is no longer present * in the adapter. * * <p>The default implementation assumes that items will never * change position and always returns {@link #POSITION_UNCHANGED}. * * @param object Object representing an item, previously returned by a call to * {@link #instantiateItem(View, int)}. * @return object's new position index from [0, {@link #getCount()}), * {@link #POSITION_UNCHANGED} if the object's position has not changed, * or {@link #POSITION_NONE} if the item is no longer present. */ public int getItemPosition(Object object) { return POSITION_UNCHANGED; }
Default return POSITION_UNCHANGED, This leads to the update of the data source , But the view doesn't change .
So my solution is to rewrite getItemPosition() This method , To return to POSITION_NONE. Of course, this method costs a lot of system , Do it every time destroyItem() Method , If the amount of data is small , It will cause a lot of unnecessary expenses .
边栏推荐
- Three-level distribution is becoming more and more popular. How should businesses choose the appropriate three-level distribution system?
- Svg optimization by svgo
- Global configuration tabbar
- 小程序启动性能优化实践
- 观测云与 TDengine 达成深度合作,优化企业上云体验
- [listening for an attribute in the array]
- Wechat applet obtains household area information
- STM32 simple multi-level menu (array table lookup method)
- C language - input array two-dimensional array a from the keyboard, and put 3 in a × 5. The elements in the third column of the matrix are moved to the left to the 0 column, and the element rows in ea
- C语言-从键盘输入数组二维数组a,将a中3×5矩阵中第3列的元素左移到第0列,第3列以后的每列元素行依次左移,原来左边的各列依次绕到右边
猜你喜欢
What are the advantages of the live teaching system to improve learning quickly?
一次 Keepalived 高可用的事故,让我重学了一遍它
Unity skframework framework (24), avatar controller third person control
一篇文章带你走进cookie,session,Token的世界
初识结构体
顶会论文看图对比学习(GNN+CL)研究趋势
Community group buying exploded overnight. How should this new model of e-commerce operate?
百度APP 基于Pipeline as Code的持续集成实践
Lepton 无损压缩原理及性能分析
Applet network data request
随机推荐
[reading notes] Figure comparative learning gnn+cl
Wechat applet obtains household area information
How to improve the operation efficiency of intra city distribution
A detailed explanation of the general process and the latest research trends of map comparative learning (gnn+cl)
Why does everyone want to do e-commerce? How much do you know about the advantages of online shopping malls?
Creation and reference of applet
基于STM32单片机的测温仪(带人脸检测)
基于宽表的数据建模应用
Android 隐私沙盒开发者预览版 3: 隐私安全和个性化体验全都要
Composition of applet code
植物大战僵尸Scratch
Thermometer based on STM32 single chip microcomputer (with face detection)
MySQL does not take effect in sorting string types
【阅读笔记】图对比学习 GNN+CL
【数组的中的某个属性的监听】
Greendao reported an error in qigsaw, could not init daoconfig
初识结构体
Uni app implements global variables
使用el-upload封装得组件怎么清空已上传附件
【js 根据对象数组中的属性进行排序】