I am implementing a ViewPager with tabs similar to the implementation provided by Google here .
My application has the following behavior. My ViewPager has 3 "pages" (fragA, fragB, fragC), and I implement 3 tabs on top of the ViewPager. The difference between google and mine is that tabs are not used to move between fragments. For example, clicking one of my tabs loads another data set into the visible fragment. I can have fragA with tab3 selected, fragB with tab2 selected and fragC with tab1 selected.
The problem is that I rotate the screen. If I am on FragmentA with the third tab selected, when I rotate the screen, I remain in the same fragment, but now the first tab is selected. I want to keep the same tab that was selected when the screen was rotated.
This is my tab management class:
public class ManagerTabs extends Fragment { private TabHost.TabContentFactory mFactory = new TabHost.TabContentFactory() { @Override public View createTabContent(String tag) { View v = new View(getActivity()); v.setMinimumWidth(0); v.setMinimumHeight(0); return v; } }; public static ManagerTabs newManager() { return new ManagerTabs(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { view = inflater.inflate(R.layout.datatabs, container, false); createTabs(); createPager(); return view; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); if (savedInstanceState != null) { currentPage = savedInstanceState.getInt("currentPage", currentPage); currentTab = savedInstanceState.getInt("currentTab", currentTab); mTabHost.setCurrentTab(currentTab); } mPager.setCurrentItem(currentPage); } private void createPager() { mPager = (ViewPager) view.findViewById(R.id.datapager); pagerAdapter = new PagerAdapter(getChildFragmentManager()); mPager.setAdapter(pagerAdapter); IconPageIndicator indicator = (IconPageIndicator) rootView.findViewById(R.id.indicator); indicator.setViewPager(pager); indicator.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { currentTab = mTabHost.getCurrentTab(); currentPage = mPager.getCurrentItem(); switch (currentPage) { case 0: ((FragmentA) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab); break; case 1: ((FragmentB) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab); break; case 2: ((FragmentC) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab); break; } } }); } private void createTabs() { mTabHost = (TabHost) view.findViewById(android.R.id.tabhost); mTabHost.setup(); mTabHost.addTab(mTabHost.newTabSpec(getString(R.string.day))setIndicator(getString(R.string.day)).setContent(mFactory)); mTabHost.addTab(mTabHost.newTabSpec(getString(R.string.month)).setIndicator(getString(R.string.month)).setContent(mFactory)); mTabHost.addTab(mTabHost.newTabSpec(getString(R.string.year)).setIndicator(getString(R.string.year)).setContent(mFactory)); mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() { public void onTabChanged(String tag) { currentTab = mTabHost.getCurrentTab(); currentPage = mPager.getCurrentItem(); switch (currentPage) { case 0: ((FragmentA) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab); break; case 1: ((FragmentB) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab); break; case 2: ((FragmentC) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab); break; } } }); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("currentPage", mPager.getCurrentItem()); outState.putInt("currentTab", mTabHost.getCurrentTab()); } }
And this is the adapter that creates the fragments:
public class PagerAdapter extends FragmentPagerAdapter implements IconPagerAdapter{ private Fragment[] currentFragment = new Fragment[3]; public PagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int index) { Fragment fragment; switch (index) { case 0: fragment = FragmentA.newInstance(); break; case 1: fragment = FragmentB.newInstance(); break; case 2: fragment = FragmentC.newInstance(); break; default: fragment = null; break; } currentFragment[index] = fragment; return fragment; } @Override public int getIconResId(int index) { switch (index) { case 0: return R.drawable.fraga; case 1: return R.drawable.fragb; case 2: return R.drawable.fragc; default: return -1; } } @Override public int getCount() { return 3; } public Fragment getCurrentFragment(int currentFrag) { return currentFragment[currentFrag]; } public Fragment[] getCurrentFragment() { return currentFragment; } }
And finally, the fragment (FragmentA, FragmentB and FragmentC) is almost identical:
public class FragmentA extends Fragment { public static FragmentA newInstance() { return new FragmentA(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { rootView = inflater.inflate(R.layout.datafragment, container, false); mTabHost = (TabHost) ((View) container.getParent().getParent()).findViewById(android.R.id.tabhost); if (savedInstanceState != null) { currentTab = savedInstanceState.getInt("currentTab"); } populateLayout(currentTab); return rootView; } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("currentTab", currentTab); } }
The problem is that all my onCreateView always called twice, and the second time they are called, the information is lost. I debugged and saw this behavior,
When I rotate the screen, for example, in FragmentA and with the third tab selected, this happens:
01 ManagerTabs -> onSaveInstanceState 02 FragmentA -> onSaveInstanceState 03 ManagerTabs -> onCreateView 04 ManagerTabs -> onViewCreated
In a call 04 (ManagerTabs -> onViewCreated) mTabHost.setCurrentTab(currentTab); is called mTabHost.setCurrentTab(currentTab); but inside onTabChanged , I get java.lang.NullPointerException because all the fragments inside the adapter are null.
What can I do so that if I rotate the screen, I can save the currently selected tab?