前提:
这次项目中采用了在fragment中添加了一个viewpager的形式,viewpager中切换的是fragment。
BUG:
退出了那个包含viewpager的fragment并重新进入,切换viewpager时,不调用fragmentpageradapter适配器的getItem()方法,在显示上,出现viewpager的显示数量增多、显示数据不正确(这个情况只在初始化fragment时,需要传递参数的情况)的情况。
调试:
fragmentpageradapter的instantiateItem(ViewGroup container, int position)方法,在调用的时候做了优化处理:
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
以上代码中,会先判断是否已经加载过这个fragment,如果加载过,就只进行attach操作,不会进行实例化,这样可以节约资源。在上面的前提下,debug到这时第二次进入到fragment后,切换内部的fragment时,在此处mFragmentManager.findFragmentByTag(name);方法返回值都不为空,所以导致了上面提到的BUG。
解决:
在实例化FragmentPagerAdapter类时,需要传递两个参数,将第一个参数设置为getChildFragmentManager()而非getFragmentManager()即可解决问题。
fragment源码中有getFragmentManager()的说明:
/**
* Return the FragmentManager for interacting with fragments associated
* with this fragment's activity. Note that this will be non-null slightly
* before {@link #getActivity()}, during the time from when the fragment is
* placed in a {@link FragmentTransaction} until it is committed and
* attached to its activity.
*
* <p>If this Fragment is a child of another Fragment, the FragmentManager
* returned here will be the parent's {@link #getChildFragmentManager()}.
*/
final public FragmentManager getFragmentManager() {
return mFragmentManager;
}
可以理解为:
getFragmentManager()是所在fragment 父容器的碎片管理,
getChildFragmentManager()是在fragment 里面子容器的碎片管理。
网友评论