我有一个 ViewPager
,其中包含 6 个页面,OffscreenPageLimit=2
(易于重现我的错误)。这 6 个页面中的所有数据都来自服务器。在 onCreateView
中,我向服务器发送请求,并在收到数据后刷新 UI。
当我选择第一个选项卡并快速切换到最后几次时,某些页面会显示错误。此时,片段中的字段 mMainLayout
不为空。
例如,在我的第一页中有一个 ListView
。当页面出错时,另一个 ListView 出现在正确的 ListView 上方。当我尝试滚动 ListView 时,只有右侧的那个(底部的)会移动。
我知道我的响应侦听器持有 mMainLayout 和一些其他视图的引用。我在方法 onCreateView 中创建了一个新的 mMainLayout,我认为片段在重新连接/还原时使用新的 mMainLayout 并删除旧的(或将其从容器中移除)。但我错了。
我知道 FragmentPagerAdapter
在 instantiateItem
中附加/重新附加片段,并在 destroyItem
中分离片段。适配器没有删除片段,也没有创建新片段。片段保留视图和视图状态本身。
我从容器中删除了 mMainLayout,将片段中的所有视图设置为空值,在 onDestroyView
中不保存任何内容。但错误仍然很容易重现。
活动:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
registerReceiver(receiver, new IntentFilter("com.souyidai.intent.action.log_fragment"));
FragmentManager fragmentManager = getFragmentManager();
mResources = getResources();
mMainPagerAdapter = new MainPagerAdapter(fragmentManager);
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mMainPagerAdapter);
mPager.setOffscreenPageLimit(CACHE_SIZE);
mIndicator = (TabPageIndicator) findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
...
}
private class MainPagerAdapter extends FragmentPagerAdapter {
public MainPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
MainConfig.TabItem tab = mTabs.get(position);
String tabType = tab.getTabType();
String code = tab.getCode();
MainConfig.TabItem.SubTabItem subTabItem = tab.getSubitem().get(0);
Fragment fragment = MainFragment.newInstance(code, subTabItem);
return fragment;
}
@Override
public CharSequence getPageTitle(int position) {
MainConfig.TabItem tab = mTabs.get(position);
return tab.getTitle();
}
@Override
public int getCount() {
return mTabs.size();
}
}
片段:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mContainer = container;
mMainLayout = inflater.inflate(R.layout.fragment_main, container, false);
...
}
@Override
public void onDestroyView() {
super.onDestroyView();
mContainer.removeView(mMainLayout);
mContainer = null;
mMainLayout = null;
mSwipeRefreshLayout = null;
mListView = null;
mHeaderLayout = null;
mFooterLayout = null;
...
}
android.support.v13.app.FragmentPagerAdapter
@Override
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) {
FragmentCompat.setMenuVisibility(fragment, false);
FragmentCompat.setUserVisibleHint(fragment, false);
}
return fragment;
}
我发现这个问题:
Android fragment onCreateView creating duplicate views on top of each other
但是我只在FragmentPagerAdapter.getItem
中创建新的片段。所以我们不同。
我通过在onCreateView方法中删除mMainLayout的所有子项(如果mMainLayout不为空),解决了这个问题。然后一切都好了。但我仍然困惑为什么会出现这个bug?
我进行了一些测试。
1. 尝试两次添加片段,应用程序崩溃并记录以下内容:java.lang.IllegalStateException: Fragment already added: ...
2. 尝试两次附加片段,系统不调用Fragment.onCreate
或Fragment.onCreateView