当前位置:网站首页>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 .
边栏推荐
- Kotlin introductory notes (V) classes and objects, inheritance, constructors
- OpenGL - Model Loading
- A keepalived high availability accident made me learn it again
- Applet global style configuration window
- Kotlin introductory notes (III) kotlin program logic control (if, when)
- 2310. The number of bits is the sum of integers of K
- H.265编码原理入门
- What are the advantages of the live teaching system to improve learning quickly?
- C语言-从键盘输入数组二维数组a,将a中3×5矩阵中第3列的元素左移到第0列,第3列以后的每列元素行依次左移,原来左边的各列依次绕到右边
- Three-level distribution is becoming more and more popular. How should businesses choose the appropriate three-level distribution system?
猜你喜欢
干货整理!ERP在制造业的发展趋势如何,看这一篇就够了
LeetCode 556. 下一个更大元素 III
Hi Fun Summer, play SQL planner with starrocks!
LeetCode 496. Next larger element I
【sourceTree配置SSH及使用】
AUTOSAR from getting started to mastering 100 lectures (103) -dbc file format and creation details
Kotlin introductory notes (VII) data class and singleton class
Creation and reference of applet
顶会论文看图对比学习(GNN+CL)研究趋势
图神经网络+对比学习,下一步去哪?
随机推荐
【数组的中的某个属性的监听】
[hungry dynamic table]
观测云与 TDengine 达成深度合作,优化企业上云体验
Unity SKFramework框架(二十三)、MiniMap 小地图工具
An article takes you into the world of cookies, sessions, and tokens
Applet network data request
LeetCode 556. Next bigger element III
微信小程序获取住户地区信息
SQL learning - case when then else
Alibaba's ten-year test brings you into the world of APP testing
利用请求头开发多端应用
植物大战僵尸Scratch
一文详解图对比学习(GNN+CL)的一般流程和最新研究趋势
一文读懂TDengine的窗口查询功能
Principle and performance analysis of lepton lossless compression
Figure neural network + comparative learning, where to go next?
Newton iterative method (solving nonlinear equations)
How to choose the right chain management software?
Android 隐私沙盒开发者预览版 3: 隐私安全和个性化体验全都要
The most comprehensive promotion strategy: online and offline promotion methods of E-commerce mall