2

I am using the following code to populate my UI with 2 fragments, the containers are FrameLayout's defined in XML. This first time this code is called i.e. when the app starts, it works fine, and both my fragments are displayed as expected. However after a configuration change(specifically, orientation), only the first fragment in the transaction is shown.

I don't think it's an issue with the fragments themselves, because if I reverse the code so one replace is called before the other or vice versa, that fragment will be displayed. So for example with the snippet from below as a guide, if I swap the mSummary and mDetails replace calls, then mDetails will be displayed and mSummary won't.

It's always the second one in the block that is missing.

// Using tablet layout
} else {
    FragmentManager fm = super.getFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.summary_container, mSummaryFragment);
    ft.replace(R.id.details_container, mDetailsFragment);
    ft.commit();
}

I'm saving the fragments in onSaveInstanceState and restoring them from the Bundle savedInstanceState when the activity is recreated. I also tried breaking the transaction into two pieces by calling commit() and then getting another FragmentTransaction object but no joy there.

Karl
  • 3,394
  • 2
  • 22
  • 31
  • Do you have the same layout between the portrait and landscape? If not, are the containers properly placed? – user Sep 16 '13 at 08:58
  • The layout changes from having one fragment above the other in their own containers to having them side by side, in their own containers. The container ids remain the same, its basically just their position on screen changes based on the orientation. The containers I refer to are `FrameLayout`'s in both XML files. – Karl Sep 16 '13 at 19:25
  • Worth noting possibly that both layouts work fine if they are the first layout used. Starting the app in either orientation is fine but as soon as the device rotates and the block of code above gets called, only the first fragment is visible. I can reverse the order I replace them and its still only the first so I assume the layout files are OK – Karl Sep 16 '13 at 19:28
  • You could, just for testing, to switch from a `replace` transaction to a combo of a `remove` + `add` transactions and see how it goes. Also, it would be interesting if you could monitor the disappearing fragment's lifecycle methods(maybe also passing through a Bundle a unique identifier to know for sure it's thatfragment) to see if it's actually built by its replace transaction. – user Sep 16 '13 at 19:38
  • I did try the remove + add method as well but with the same result. I'll see if I can spot anything with the life cycle of the fragment as you mention. – Karl Sep 16 '13 at 20:12
  • 6
    Can you show the code how you restore the Fragments in onCreate using savedInstanceState? It sounds to me that there is the problem. – Steve Benett Sep 17 '13 at 14:28
  • 1
    Just a guess, but do you use setRetainInstance(true) in your fragments? – stoilkov Sep 22 '13 at 15:24
  • @stoilkov was right in my case. The fragment has also another object id according to the debugger, after you init the data to the fragment, call setRetainInstance = true and then call the transaction, it will be the same Object :) – CaipiDE Mar 23 '21 at 21:29

2 Answers2

1

So for anyone coming across this at a later stage...

I finally manage to fix this by creating a new instance of the fragment and restoring it's state using a Fragment.SavedState object. So:

        if (mSummaryFragment.isAdded() && mDetailsFragment.isAdded()) {
            Fragment.SavedState sumState = getSupportFragmentManager().saveFragmentInstanceState(mSummaryFragment);
            Fragment.SavedState detState = getSupportFragmentManager().saveFragmentInstanceState(mDetailsFragment);

            mSummaryFragment = new SummaryFragment();
            mSummaryFragment.setInitialSavedState(sumState);

            mDetailsFragment = new DetailsFragment();
            mDetailsFragment.setInitialSavedState(detState);
        }

        FragmentTransaction ft = mFragmentManager.beginTransaction();

        ft.add(R.id.summary_container, mSummaryFragment);
        ft.add(R.id.details_container, mDetailsFragment);

        ft.commit();

I do not understand why this works and the old method doesn't, however this may be helpful for someone else.

Karl
  • 3,394
  • 2
  • 22
  • 31
-1

this should work and orientation change will not affect the fragment., if you face any problem just let me know.

public class MainActivity extends FragmentActivity {
     Fragment fragment = new Fragment1();
     Fragment fragment2=new Fragment2();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

          FragmentManager fm = super.getSupportFragmentManager();
            FragmentTransaction ft = fm.beginTransaction();
            ft.replace(R.id.frame1, fragment);
            ft.replace(R.id.frame2, fragment2);
            ft.commit();

    }
    public void onSaveInstanceState(Bundle outState){
        getSupportFragmentManager().putFragment(outState,"fragment1",fragment);
        getSupportFragmentManager().putFragment(outState,"fragment2",fragment2);
    }
    public void onRetoreInstanceState(Bundle inState){
        fragment = getSupportFragmentManager().getFragment(inState,"fragment1");
        fragment2 = getSupportFragmentManager().getFragment(inState,"fragment2");

    }
     class Fragment1 extends Fragment{

            @Override
            public void onActivityCreated(Bundle savedInstanceState) {

                super.onActivityCreated(savedInstanceState);
            }
        ListView listView;
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                    Bundle savedInstanceState) {
                View view=inflater.inflate(R.layout.summary_view,container,false);
                return view;
            }

            @Override
            public void onViewCreated(View view, Bundle savedInstanceState) {

                super.onViewCreated(view, savedInstanceState);
            }

        }

     class Fragment2 extends Fragment{

            @Override
            public void onActivityCreated(Bundle savedInstanceState) {

                super.onActivityCreated(savedInstanceState);
            }
        ListView listView;
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                    Bundle savedInstanceState) {
                View view=inflater.inflate(R.layout.detail_view,container,false);
                return view;
            }

            @Override
            public void onViewCreated(View view, Bundle savedInstanceState) {

                super.onViewCreated(view, savedInstanceState);
            }

        }

}
user1918096
  • 153
  • 1
  • 3
  • 10