4

I have a working app which I'm trying to optimise for use on tablet's by inflating a different layout as per the Android documentation.

The issue I have is that when in portrait orientation, my view is populated by a ViewPager, and my two important fragments and their data in it's adapter. When in landscape orientation, the View is populated by the same two fragments, but side by side in one layout instead of in a ViewPager. I'm saving the fragments in onSaveInstanceState, and retrieving them again like this:

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    if (mSummaryFragment != null) {
        getFragmentManager().putFragment(outState, TAG_SUMMARY, mSummaryFragment);
    }

    if (mDetailsFragment != null) {
        getFragmentManager().putFragment(outState, TAG_DETAILS, mDetailsFragment);
    }
}

Retrieving in onCreate...

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (savedInstanceState != null) {
        mSummaryFragment = (SummaryFragment) getFragmentManager().getFragment(savedInstanceState, TAG_SUMMARY);
        mDetailsFragment = (DetailsFragment) getFragmentManager().getFragment(savedInstanceState, TAG_DETAILS);
    } else {
        mSummaryFragment = new SummaryFragment();
        mDetailsFragment = new DetailsFragment();
    }
}

I should mention that these fragments are nested, because my main activity is in fact a fragment itself. As of 4.2 I believe this shouldn't be an issue but I'm not 100% savvy on the lifecycle. My view is populated like this:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    setHasOptionsMenu(true);

    View result = inflater.inflate(R.layout.main, container, false);
    ViewPager pager = (ViewPager) result.findViewById(R.id.viewpager);
    if (null != pager) {
        pager.setAdapter(new PagerAdapter(getFragmentManager(), mUpdater));
    } else {
        FragmentManager fm = getFragmentManager();
        fm.beginTransaction().add(R.id.summary_container, mSummaryFragment).commit();
        fm.beginTransaction().add(R.id.details_container, mDetailsFragment).commit();
    }

    if (savedInstanceState == null) {
        Refresh(0,0);
    }

    return (result);
}

The PagerAdapter's getItem method looks like this:

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                return mSummaryFragment;

            case 1:
                return mDetailsFragment;
        }
        return null;
    }

Everything works fine on first launch, but when the orientation changes, I get this error in logcat regardless of which way the orientation is changing (portrait -> landscape or vice-versa):

java.lang.IllegalStateException: Can't change container ID of fragment SummaryFragment{40dd1800 #1 id=0x7f0b004a android:switcher:2131427400:0}: was 2131427402 now 2131427400

I'm not entirely sure that this is the best way to do what I want - however the saving of fragments into a bundle and retrieving them was a trick I spotted in the Google IO 2013 source code so I hope it's at least partly right.

Karl
  • 3,394
  • 2
  • 22
  • 31
  • http://stackoverflow.com/questions/9906254/illegalstateexception-cant-change-container-id-of-fragment – Arash GM Aug 12 '13 at 04:46

2 Answers2

1

I found solution. For portrait and landscape mode I use ViewPager, but I override in page adapter method:

public float getPageWidth(int position)

In normal state this method return 1.0f and ViewPager show one page, but when method return 0.5f - two pages. In portrait mode set PAGE_WIDTH_FULL_SCREEN and in landscape PAGE_WIDTH_HALF_SCREEN, when you create adapter in activity. The sample code with overrided public methods below:

public class ViewPagerAdapter extends FragmentPagerAdapter {

public static final float PAGE_WIDTH_FULL_SCREEN = 1.0f;
public static final float PAGE_WIDTH_HALF_SCREEN = 0.5f;

private FragmentManager fragmentManager;
private ArrayList<Fragment> fragments;
private float pageWidth = PAGE_WIDTH_FULL_SCREEN;

public ViewPagerAdapter(FragmentManager fm, ArrayList<Fragment> fragments) {
    super(fm);
    this.fragmentManager = fm;
    this.fragments = fragments;
}

public void setPageWidth(float pageWidth) {
    this.pageWidth = pageWidth;
}

@Override
public float getPageWidth(int position) {
    return pageWidth;
}

@Override
public Fragment getItem(int position) {
    return fragments.get(position);
}

@Override
public int getCount() {
    return fragments.size();
}
}
Pavel Shysh
  • 196
  • 2
  • 13
-3

You'll need to remove it first.

if (null != pager) {
    pager.setAdapter(new PagerAdapter(getFragmentManager(), mUpdater));
} else {
    FragmentManager fm = getFragmentManager();
    fm.beginTransaction().remove(mSummaryFragment).add(R.id.summary_container, mSummaryFragment).commit();
    fm.beginTransaction().remove(mDetailsFragment).add(R.id.details_container, mDetailsFragment).commit();
}
Jon
  • 1,398
  • 9
  • 14