I have 6 pages in ViewPager
and OffscreenPageLimit=2
(easy to reproduce my error).
all data on 6 pages from the server. In onCreateView
I send a request to the server and update the user interface when receiving data from the server.
When I select the first tab and quickly change it several times, some pagers do not display correctly. And while my mMainLayout
field in the fragment is not null.
For example, I have a ListView
on my first page. When the page is incorrect, another ListView is at the top of the right ListView. When I try to scroll through the ListView, only the right (bottom) moves.
I know that my response listener contains a link to mMainLayout and some other views, I create a new mMainLayout in the onCreateView method, I thought the fragment uses the new mMainLayout when it rejoins / restores and removes the old one (or removes it from the container). But I was wrong.
I know that FragmentPagerAdapter
attach / reattach fragment in instantiateItem
and detach in destroyItem
. The adapter did not delete the fragment. The adapter did not create a new fragment. The snippet saves the view and views the states.
I remove mMainLayout from the container and set all the views in my zero snippet to onDestroyView
and don't save anything to onSaveInstanceState
. But still easy to reproduce the error.
activity:
@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(); } }
fragment:
@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; }
I find this:
Android onCreateView snippet creating repeating views on each other
But I only create a new fragment in FragmentPagerAdapter.getItem
. So we are different.
I solve this by removing all the children of mMainLayout if mMainLayout is not null in the onCreateView method. Thatβs all right. But I'm still confused, why is this error happening?
I did some tests.
1. try to add fragment twice, application crash and log: java.lang.IllegalStateException: Fragment already added: ...
2. try to insert the fragment twice, the system does not call Fragment.onCreate
or Fragment.onCreateView