I came up with a solution to achieve a better memory managed solution (adapter-based) for having multiple user journeys saved at the same time (independent tabs with something that represents backstacks). I scrapped using the FragmentManager as it was not conducive to this behavior. I will leave my answer here in case anyone else runs into a similar problem of needing this idea of multiple backstacks using ViewPagers with FragmentStatePagerAdapter - one viewpager for each tab in their app (this can still be cleaned up more but you can get the jist):
Primary Activity:
public class MultiTabbedActivity extends FragmentActivity implements NavigationFragment.OnNavigationSelectedListener
{
private Page1Fragment mPage1;
private Page2Fragment mPage2;
private CustomFragment mCurrent;
private String mNav;
private List<CustomFragment> mPage1BackStack;
private List<CustomFragment> mPage2BackStack;
private CustomViewPager mPagerPage1;
private CustomViewPager mPagerPage2;
private boolean mUpdating = false;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// initialize the backstacks
mPage1BackStack = new ArrayList<CustomFragment>();
mPage2BackStack = new ArrayList<CustomFragment>();
mPage1 = new Page1Fragment();
mPage2 = new Page2Fragment();
mPage1BackStack.add(mPage1);
mPage2BackStack.add(mPage2);
mPagerPage1 = (CustomViewPager) findViewById(R.id.page1_fragment);
mPagerPage2 = (CustomViewPager) findViewById(R.id.page2_fragment);
mPagerPage1.setOffscreenPageLimit(3); //Customizable to determine how many
mPagerPage2.setOffscreenPageLimit(3); //fragments you want to hold in memory
mPagerPage1.setAdapter(new CustomFragmentAdapter(getSupportFragmentManager(), mPage1BackStack));
mPagerPage2.setAdapter(new CustomFragmentAdapter(getSupportFragmentManager(), mPage2BackStack));
displayPager(mPagerPage1);
mCurrent = mPage1;
mNav = GlobalConstants.PAGE_PAGE1;
}
private void displayPager(ViewPager pager)
{
mPagerPage1.setVisibility(ViewPager.GONE);
mPagerPage2.setVisibility(ViewPager.GONE);
pager.setCurrentItem(pager.getAdapter().getCount() - 1);
pager.getAdapter().notifyDataSetChanged();
pager.setVisibility(ViewPager.VISIBLE);
}
@Override
public void onNavSelected(String page)
{
if (page != null && page != "" && !mUpdating)
{
// Determine the Fragment selected
if (page.equalsIgnoreCase(GlobalConstants.PAGE_PAGE1))
{
mNav = GlobalConstants.PAGE_PAGE1;
displayPager(mPagerPage1);
mCurrent = mPage1BackStack.get(mPage1BackStack.size() - 1);
}
else if (page.equalsIgnoreCase(GlobalConstants.PAGE_PAGE2))
{
mNav = GlobalConstants.PAGE_PAGE2;
displayPager(mPagerPage2);
mCurrent = mPage2BackStack.get(mPage2BackStack.size() - 1);
}
}
}
@Override
public void onBackPressed()
{
PageFragment navFrag = null;
// Update the Navigation Menu to indicate the currently visible
// Fragment
try
{
mUpdating = true;
if (mPage1BackStack.size() > 1 && mNav.equalsIgnoreCase(GlobalConstants.PAGE_PAGE1))
{
mPagerPage1.setCurrentItem(mPage1BackStack.size() - 2);
mPage1BackStack.remove(mPage1BackStack.size() - 1);
navFrag = mPage1BackStack.get(mPage1BackStack.size() - 1);
mPagerPage1.setAdapter(new CustomFragmentAdapter(getSupportFragmentManager(), mPage1BackStack));
}
else if (mPage2BackStack.size() > 1 && mNav.equalsIgnoreCase(GlobalConstants.PAGE_PAGE2))
{
mPagerPage2.setCurrentItem(mPage2BackStack.size() - 2);
mPage2BackStack.remove(mPage2BackStack.size() - 1);
navFrag = mPage2BackStack.get(mPage2BackStack.size() - 1);
mPagerPage2.setAdapter(new CustomFragmentAdapter(getSupportFragmentManager(), mPage2BackStack));
}
else
{
super.onBackPressed();
}
if (navFrag != null)
mCurrent = navFrag;
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
mUpdating = false;
}
}
public void updateFragment(PageFragment newFragment)
{
if (mNav.equalsIgnoreCase(GlobalConstants.PAGE_PAGE1))
{
mPage1BackStack.add(newFragment);
displayPager(mPagerPage1);
}
else if (mNav.equalsIgnoreCase(GlobalConstants.PAGE_PAGE2))
{
mPage2BackStack.add(newFragment);
displayPager(mPagerPage2);
}
mCurrent = newFragment;
}
}
CustomViewPager:
public class CustomViewPager extends ViewPager {
private boolean enabled;
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
this.enabled = false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onTouchEvent(event);
}
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onInterceptTouchEvent(event);
}
return false;
}
public void setPagingEnabled(boolean enabled) {
this.enabled = enabled;
}
}
CustomAdapter:
public class CustomFragmentAdapter extends FragmentStatePagerAdapter
{
List<CustomFragment> mFragments;
public CustomFragmentAdapter(FragmentManager fm, List<CustomFragment> fragments)
{
super(fm);
mFragments = fragments;
}
public List<PageFragment> getmFragments()
{
return mFragments;
}
public void setmFragments(List<CustomFragment> mFragments)
{
this.mFragments = mFragments;
}
@Override
public int getCount()
{
return mFragments.size();
}
@Override
public Fragment getItem(int position)
{
return (Fragment) (mFragments.get(position));
}
}
UI (wrapped inside a linear layout):
<fragment
android:id="@+id/navigation_fragment"
android:name="your.package.here.NavigationFragment"
android:layout_width="70dp"
android:layout_height="match_parent" />
<FrameLayout
android:id="@+id/page_fragment"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="2" >
<your.package.here.CustomViewPager
android:id="@+id/page1_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<your.package.here.CustomViewPager
android:id="@+id/page2_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</FrameLayout>