1

I want different layouts for portrait and landscape mode. Also I want my fragments to save their states where orientation changes. Here is layout\activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

And it is layout-land\activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <fragment
        android:id="@+id/fragment1"
        android:name="com.example.fragmentorientationchangetest.Fragment1"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <fragment
        android:id="@+id/fragment2"
        android:name="com.example.fragmentorientationchangetest.Fragment2"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

</LinearLayout>

Here is MainActivity:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (findViewById(R.id.container) != null) {

            if (savedInstanceState != null) {
                return;
            }
            Fragment1 fragment1 = new Fragment1();
            getFragmentManager().beginTransaction()
                    .add(R.id.container, fragment1, "tag1").commit();
        }

    }

And it is Fragment1:

public class Fragment1 extends Fragment{

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

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View  view = inflater.inflate(R.layout.fragment1, container, false);

        return view;
    }

}

Fragment2 is same as Fragment1.

However when I start in portrait mode and rotate to landscape mode, the app crashes. The problem is because of using setRetainInstance(true), It saves the reference to R.id.container, but this container does not exist in landscape layout And this is output:

10-02 15:52:50.679: E/AndroidRuntime(2531): FATAL EXCEPTION: main
10-02 15:52:50.679: E/AndroidRuntime(2531): Process: com.example.fragmentorientationchangetest, PID: 2531
10-02 15:52:50.679: E/AndroidRuntime(2531): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.fragmentorientationchangetest/com.example.fragmentorientationchangetest.MainActivity}: 
    java.lang.IllegalArgumentException: No view found for id 0x7f090000 (com.example.fragmentorientationchangetest:id/container) for fragment Fragment1{52874ecc #0 id=0x7f090000 tag1}

But according to this I must use onRetainInstance in fragments to handle orientation change. What should I do now?

Thanks in advance!

Community
  • 1
  • 1
Misagh Emamverdi
  • 3,654
  • 5
  • 33
  • 57

1 Answers1

0

On this line:

getFragmentManager().beginTransaction()
        .add(R.id.container, fragment1, "tag1").commit();

You're adding the Fragment to the ViewGroup with ID container. When the Activity is destroyed and recreated, it will try to re-attach that Fragment to a ViewGroup with ID container. However, in your landscape layout, you don't have a container ViewGroup -- you have a Fragment defined in XML. Replace:

<fragment
    android:id="@+id/fragment1"
    android:name="com.example.fragmentorientationchangetest.Fragment1"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1" />

with:

<FrameLayout
    android:id="@+id/container"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1" />

So that the Activity is able to re-attach the Fragment.

Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • But I if rotate the screen when I am in fragment2 in portrait mode, It will be added in left pane. – Misagh Emamverdi Oct 02 '14 at 18:21
  • 1
    Hmm, that is quite true. I suppose that's why they use a new Activity in the example code for this instead of swapping fragments. Perhaps the easiest workaround would be to have two FrameLayouts in portrait with different IDs? And then hide() the first fragment and add() the new fragment in the same transaction? – Kevin Coppock Oct 02 '14 at 18:25
  • Yes, As you said I think it is possible by using two framelayout that cover each other dynamically. But I'll really get surprised if there isn't any other handy solution, because it may not be a rare case. – Misagh Emamverdi Oct 02 '14 at 19:00