I have a simple Pager layout in my application, which should change depending on my AppState. The app has two main states, LoggedIn and LoggedOut. If the AppState is LoggedOut then my tab layout should be built based on two fragments fragment_login
and fragment_about
. If the App State is LoggedIn then the tab layout should be built based on different tabs fragment_main
, fragment_details
, fragment_about
, fragment_logout
.
I can initialise the app with either of these states, and everything works as expected. However, the problem is dynamically changing these layouts at Runtime after the user has logged in.
The Tab layouts change captions correctly, but some of the old tab fragments persist.
SETUP
My Class connecting Fragments and their respective caption
private class FragmentList {
Class fClass;
String fName;
public FragmentList(Class c, String n) {
fClass = c;
fName = n;
}
}
My SectionsAdapter
You can see I'm currently experimenting with passing the ArrayList as a parameter in order to be able to reloadtabs()
, but this still isn't working
public class SectionsPagerAdapter extends FragmentPagerAdapter {
ArrayList<FragmentList> tabList;
public SectionsPagerAdapter(FragmentManager fm, ArrayList<FragmentList> fragList) {
super(fm);
tabList = fragList;
}
public void reloadTabs() {
tabList = listFragments_CurrentlyActive;
this.notifyDataSetChanged();
}
@Override
public Fragment getItem(int position) {
Fragment fragment = null;
Class newFragmentClass;
if (position <= tabList.size()) {
newFragmentClass = tabList.get(position).fClass;
} else {
newFragmentClass = tabList.get(0).fClass;
}
try {
fragment = (Fragment) newFragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
//Bundle args = new Bundle();
//args.putInt(ARG_SECTION_NUMBER, sectionNumber);
//fragment.setArguments(args);
return fragment;
}
@Override
public int getCount() {
return tabList.size();
}
@Override
public CharSequence getPageTitle(int position) {
if (position <= tabList.size()) {
return tabList.get(position).fName;
} else {
return "Unknown";
}
}
}
Initialising the Fragment Lists
Note: each fragment has its own public static string for FRAGMENTNAME
private ArrayList<FragmentList> listFragmentsLoggedOut = new ArrayList<>();
private ArrayList<FragmentList> listFragmentsLoggedIn = new ArrayList<>();
listFragmentsLoggedOut.add(new FragmentList(fragment_login.class, fragment_login.FRAGMENT_NAME));
listFragmentsLoggedOut.add(new FragmentList(fragment_about.class, fragment_about.FRAGMENT_NAME));
listFragmentsLoggedIn.add(new FragmentList(fragment_main.class, fragment_main.FRAGMENT_NAME));
listFragmentsLoggedIn.add(new FragmentList(fragment_details.class, fragment_details.FRAGMENT_NAME));
listFragmentsLoggedIn.add(new FragmentList(fragment_about.class, fragment_about.FRAGMENT_NAME));
listFragmentsLoggedIn.add(new FragmentList(fragment_logout.class, fragment_logout.FRAGMENT_NAME));
Building the TabLayouts
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initApp();
refreshTabsBasedOnNewState();
}
//Separate method that can be called from elsewhere to update the Tabs
public void refreshTabsBasedOnNewState() {
//Can swap these and the app displays and functions correctly.
listFragments_CurrentlyActive = listFragments_LoggedOut;
//listFragments_CurrentlyActive = listFragments_LoggedIn;
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager(), listFragments_CurrentlyActive);
//update adapter class
mSectionsPagerAdapter.reloadTabs();
sectionsAdapterACTIVE.notifyDataSetChanged();
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(sectionsAdapterACTIVE);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
}
THE CURRENT OUTPUT
When the App is hardcoded to be LoggedIn
then the two fragments and tabs display correctly. Same with the App being hardcoded to be LoggedOut
. However, when I try and change the layout, by changing the value of listFragments_CurrentlyActive
then I get the following behaviour:
- Tabs increase from 2 to 4 and have the correct captions (and ordering)
- The associated Fragments are 2 of the original ones, and 2 of the new ones.
Effectively, the Tabs are correct, but the fragments being shown are that of:
fragment_login
, fragment_about
, fragment_about
, fragment_logout
.
So you can see that the 2 additional fragments are being added correctly, but the two initial ones still reference the LoggedOut
fragments.
There is probably a very simple solution, where I need to update the adapter somewhere with mSectionsPagerAdapter.notifyDataSetChanged()
, or rebuild it, but I'm not finding a fix anywhere. Many thanks. J
EDIT
I've even tried creating the adapters at the start, so they are totally independent, but still the same behaviour occurs
SectionsPagerAdapter sectionsAdapter_LoggedOut = new SectionsPagerAdapter(getSupportFragmentManager(), listFragmentsLoggedOut);
SectionsPagerAdapter sectionsAdapter_LoggedIn = new SectionsPagerAdapter(getSupportFragmentManager(), listFragmentsLoggedIn);
SectionsPagerAdapter sectionsAdapterACTIVE;
sectionsAdapterACTIVE = (AppState.isLoggedIn) ? sectionsAdapter_LoggedIn : sectionsAdapter_LoggedOut
Could it be an issue with the fragment caching in getSupportFragmentManager()
?
EDIT 2
Added this Image to help visualise the issue. Not sure if I was clear enough beforehand.