FragmentStatePagerAdapter的刷新问题
来源:互联网 发布:微信域名检测原理 编辑:程序博客网 时间:2024/05/22 01:49
众所周知,FragmentStatePagerAdapter是谷歌官方专门为Fragment和ViewPager推出的Adapter,其特点是为Fragment提供缓存,避免重复加载Fragment。这个我们从源代码就可以看得出来:
@Override public Object instantiateItem(ViewGroup container, int position) { // If we already have this item instantiated, there is nothing // to do. This can happen when we are restoring the entire pager // from its saved state, where the fragment manager has already // taken care of restoring the fragments we previously had instantiated. if (mFragments.size() > position) { // 存在缓存表示该Fragment已经加载过了 // 值得注意的是,这个地方Fragment的缓存是与position绑定在一起的 Fragment f = mFragments.get(position); if (f != null) { return f; } } if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } Fragment fragment = getItem(position); if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment); if (mSavedState.size() > position) { Fragment.SavedState fss = mSavedState.get(position); if (fss != null) { //Fragment未加载,但是存在缓存的状态信息 fragment.setInitialSavedState(fss); } } while (mFragments.size() <= position) { mFragments.add(null); } fragment.setMenuVisibility(false); fragment.setUserVisibleHint(false); mFragments.set(position, fragment); mCurTransaction.add(container.getId(), fragment); return fragment; }
这就是FragmentStatePagerAdapter加载缓存的代码,其中两个关键点,我都加了中文注释。在这里我要讲的是第一个地方,也就是Fragment是和position绑定在一起的,这样的话就会有一个问题,当我们想要隐藏或者显示(插入)其中某一个Fragment,我们就必须要让所有的Fragment重新走一遍生命周期。
这是因为,想要刷新ViewPager的Fragment必须修改getItemPosition(Object object)这个方法,使其返回POSITION_NONE,但是这样的话,所有的Fragment都会先被remove,然后再重新add。
/** * 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. */ public int getItemPosition(Object object) { return POSITION_UNCHANGED; }
然儿这并不是我们想要,因此就有必要寻找一种替代方案。我们依然可以从getItemPosition这个方法入手,getItemPosition返回值表示的是page的位置,也就是说我们可以用这个方法来调整page的位置,而fragment也不需要重新加载。
既然知道问题在哪,只要对症下药就好了。修改一下FragmentStatePagerAdapter的部分逻辑即可,具体代码如下:
/** * Description: Copied from android.support.v4.app.FragmentStatePagerAdapter, Fix bug for that fragments cache not refreshed when adapter items's position changed. * FixBug#修复Fragment的位置更新而缓存未更新导致显示错误以及crash的问题 * Author: xuqingqi * E-mail: xuqingqi01@gmail.com * Date: 2017/12/8 */@Keeppublic abstract class FragmentStatePagerAdapterCompat extends PagerAdapter { private static final String TAG = FragmentStatePagerAdapterCompat.class.getSimpleName(); private static final boolean DEBUG = false; private final FragmentManager mFragmentManager; private FragmentTransaction mCurTransaction = null; private SparseArray<Fragment.SavedState> mSavedState = new SparseArray<Fragment.SavedState>(); private SparseArray<Fragment> mFragments = new SparseArray<Fragment>(); private Fragment mCurrentPrimaryItem = null; public FragmentStatePagerAdapterCompat(FragmentManager fm) { mFragmentManager = fm; } /** * Return the Fragment associated with a specified position. */ public abstract Fragment getItem(int position); /** * Return a unique identifier for the item at the given position. * * <p>The default implementation returns the given position. * Subclasses should override this method if the positions of items can change.</p> * * @param position Position within this adapter * @return Unique identifier for the item at position */ //添加一个方法,将Fragment和Id绑定在一起而不是position public int getItemId(int position) { return position; } @Override public void startUpdate(ViewGroup container) { if (container.getId() == View.NO_ID) { throw new IllegalStateException("ViewPager with adapter " + this + " requires a view id"); } } @Override public Object instantiateItem(ViewGroup container, int position) { // If we already have this item instantiated, there is nothing // to do. This can happen when we are restoring the entire pager // from its saved state, where the fragment manager has already // taken care of restoring the fragments we previously had instantiated. int itemId = getItemId(position); Fragment f = mFragments.get(itemId); if (f != null) { return f; } if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } Fragment fragment = getItem(position); if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment); Fragment.SavedState fss = mSavedState.get(itemId); if (fss != null) { fragment.setInitialSavedState(fss); } fragment.setMenuVisibility(false); fragment.setUserVisibleHint(false); mFragments.put(itemId, fragment); mCurTransaction.add(container.getId(), fragment); return fragment; } @Override public void destroyItem(ViewGroup container, int position, Object object) { Fragment fragment = (Fragment) object; if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object + " v=" + ((Fragment)object).getView()); int index = mFragments.indexOfValue(fragment); if (index >= 0) { int itemId = mFragments.keyAt(index); mSavedState.put(itemId, fragment.isAdded() ? mFragmentManager.saveFragmentInstanceState(fragment) : null); mFragments.remove(itemId); } mCurTransaction.remove(fragment); } @Override public void setPrimaryItem(ViewGroup container, int position, Object object) { Fragment fragment = (Fragment)object; if (fragment != mCurrentPrimaryItem) { if (mCurrentPrimaryItem != null) { mCurrentPrimaryItem.setMenuVisibility(false); mCurrentPrimaryItem.setUserVisibleHint(false); } if (fragment != null) { fragment.setMenuVisibility(true); fragment.setUserVisibleHint(true); } mCurrentPrimaryItem = fragment; } } @Override public void finishUpdate(ViewGroup container) { if (mCurTransaction != null) { mCurTransaction.commitNowAllowingStateLoss(); mCurTransaction = null; } } @Override public boolean isViewFromObject(View view, Object object) { return ((Fragment)object).getView() == view; } @Override public Parcelable saveState() { Bundle state = null; if (mSavedState.size() > 0) { state = new Bundle(); for (int i=0; i< mSavedState.size(); i++) { int itemId = mFragments.keyAt(i); Fragment.SavedState ss = mSavedState.get(itemId); if (ss != null) { String key = "s" + itemId; state.putParcelable(key, ss); } } } for (int i=0; i< mFragments.size(); i++) { int itemId = mFragments.keyAt(i); Fragment f = mFragments.get(itemId); if (f != null && f.isAdded()) { if (state == null) { state = new Bundle(); } String key = "f" + itemId; mFragmentManager.putFragment(state, key, f); } } return state; } @Override public void restoreState(Parcelable state, ClassLoader loader) { if (state != null) { Bundle bundle = (Bundle)state; bundle.setClassLoader(loader); mSavedState.clear(); mFragments.clear(); Iterable<String> keys = bundle.keySet(); for (String key: keys) { if (key.startsWith("f")) { int index = Integer.parseInt(key.substring(1)); Fragment f = mFragmentManager.getFragment(bundle, key); if (f != null) { f.setMenuVisibility(false); mFragments.put(index, f); } else { Log.w(TAG, "Bad fragment at key " + key); } } else if (key.startsWith("s")) { int index = Integer.parseInt(key.substring(1)); Parcelable parcelable = bundle.getParcelable(key); if (parcelable instanceof Fragment.SavedState) { mSavedState.put(index, (Fragment.SavedState) parcelable); } } } } }}
阅读全文
0 0
- FragmentStatePagerAdapter的刷新问题
- Android FragmentStatePagerAdapter.notifyDataSetChanged()刷新数据的问题
- FragmentPagerAdapter与FragmentStatePagerAdapter的区别+ViewPager数据刷新问题详解
- android 解决FragmentStatePagerAdapter 刷新无效问题
- FragmentStatePagerAdapter.notifyDataSetChanged不刷新页面的解决办法
- FragmentStatePagerAdapter.notifyDataSetChanged不刷新页面的解决办法
- FragmentStatePagerAdapter 无法更新问题
- Android FragmentStatePagerAdapter的写法
- FragmentStatePagerAdapter的使用
- FragmentStatePagerAdapter
- FragmentStatePagerAdapter
- FragmentPagerAdapter和FragmentStatePagerAdapter的区别
- FragmentPagerAdapter 与FragmentStatePagerAdapter 的不同
- FragmentPagerAdapter和FragmentStatePagerAdapter的区别
- FragmentPagerAdapter和FragmentStatePagerAdapter的区别
- FragmentPagerAdapter和FragmentStatePagerAdapter的区别
- FragmentPagerAdapter和FragmentStatePagerAdapter的区别
- FragmentStatePagerAdapter与FragmentPagerAdapter的区别
- 旋转 div 元素
- git小技巧:git blame && git show 查看某一行代码的修改历史
- iOS AppIcon 和 LaunchImage设置查询
- shell脚本实践一(mac下php版本切换)
- c语言操作符小归纳
- FragmentStatePagerAdapter的刷新问题
- SSRS-在数据表中增加排序
- Unity3d Mesh、Texture、UI 压缩降低内存
- postgreSql性能优化提升技巧指南
- 解决telnet提示Escape character is ‘^]’.
- Linux Shell格式化Json
- 官网Mysql并配置使用以及如何重装
- 【字符串】面试题之键值对(”key = valude”)字符串
- Hamming Distance 汉明距离【各种算法】