Android support lib bug causing crash on orientation change – A workaround

Orientation changes can cause all kinds of problems if you are not careful when implementing an android app. Usually the fault is yours but this post is about a nasty crash caused by a bug in the android support v4 lib that I recently encountered in a project I was working on.

The setup of the app was pretty ordinary: A MainActivity extending ActionBarActivity (which in turn extends FragentActivity from v4 lib) and two different Fragments (one for portrait and one for landscape) defined in the layout xml files (layout/activity_main.xml and layout-land/activity_main.xml).

MainActivity.java

package com.jayway.rotationcrashworkaround;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends ActionBarActivity {

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

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
   getMenuInflater().inflate(R.menu.menu_main, menu);
   return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
   int id = item.getItemId();
   if (id == R.id.action_dialog) {
     TestDialogFragment d = TestDialogFragment.newInstance();
     d.show(getSupportFragmentManager(), "dialog");
     return true;
   }
   return super.onOptionsItemSelected(item);
 }
}

layout/activity_main.xml

<fragment
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/main_portrait"
  android:name="com.jayway.rotationcrashworkaround.MainPortraitFragment"
  android:layout_width="match_parent"
  android:layout_height="match_parent" />

layout-land/activity_main.xml

<fragment
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/main_landscape"
  android:name="com.jayway.rotationcrashworkaround.MainLandscapeFragment"
  android:layout_width="match_parent"
  android:layout_height="match_parent" />

The crash occurs when rotating the device while there is a DialogFragment open (TestDialogFragment triggered in the onOptionsItemSelected() method above). Here is the stacktrace:

01-18 11:20:39.653 20147-20147/com.jayway.rotationcrashworkaround E/AndroidRuntime﹕ FATAL EXCEPTION: main
 Process: com.jayway.rotationcrashworkaround, PID: 20147
 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.jayway.rotationcrashworkaround/com.jayway.rotationcrashworkaround.MainActivity}: android.view.InflateException: Binary XML file line #14: Error inflating class fragment
 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2237)
 at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2286)
 at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3828)
 at android.app.ActivityThread.access$900(ActivityThread.java:144)
 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1252)
 at android.os.Handler.dispatchMessage(Handler.java:102)
 at android.os.Looper.loop(Looper.java:212)
 at android.app.ActivityThread.main(ActivityThread.java:5135)
 at java.lang.reflect.Method.invokeNative(Native Method)
 at java.lang.reflect.Method.invoke(Method.java:515)
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:877)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:693)
 at dalvik.system.NativeStart.main(Native Method)
 Caused by: android.view.InflateException: Binary XML file line #14: Error inflating class fragment
 at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:713)
 at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
 at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
 at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
 at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
 at android.support.v7.app.ActionBarActivityDelegateBase.setContentView(ActionBarActivityDelegateBase.java:228)
 at android.support.v7.app.ActionBarActivity.setContentView(ActionBarActivity.java:102)
 at com.jayway.rotationcrashworkaround.MainActivity.onCreate(MainActivity.java:20)
 at android.app.Activity.performCreate(Activity.java:5231)
 at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2201)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2286)
            at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3828)
            at android.app.ActivityThread.access$900(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1252)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:212)
            at android.app.ActivityThread.main(ActivityThread.java:5135)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:877)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:693)
            at dalvik.system.NativeStart.main(Native Method)
 Caused by: java.lang.IllegalStateException: Fragment com.jayway.rotationcrashworkaround.MainLandscapeFragment did not create a view.
 at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2189)
 at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:297)
 at android.support.v7.app.ActionBarActivity.onCreateView(ActionBarActivity.java:547)
 at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:685)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
            at android.support.v7.app.ActionBarActivityDelegateBase.setContentView(ActionBarActivityDelegateBase.java:228)
            at android.support.v7.app.ActionBarActivity.setContentView(ActionBarActivity.java:102)
            at com.jayway.rotationcrashworkaround.MainActivity.onCreate(MainActivity.java:20)
            at android.app.Activity.performCreate(Activity.java:5231)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2201)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2286)
            at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3828)
            at android.app.ActivityThread.access$900(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1252)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:212)
            at android.app.ActivityThread.main(ActivityThread.java:5135)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:877)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:693)
            at dalvik.system.NativeStart.main(Native Method)

After some investigation and google searching I found a bug filed describing the same problem. It was dated december 5, 2011 and the cause of the problem was pretty well described. In short the open DialogFragment is mistaken for the Fragment that is supposed to be inflated during orientation change and view creation and this leads to the crash. Unfortunately no solution or workaround was to be found.

I tested some more and it seemed that the crash only occurred if the device had not previously been rotated when the DialogFragment was opened, i.e. the landscape fragment had not yet been inflated. This led me to try adding the landscape fragment to the portrait layout (with height and width 0) and vice versa.

layout/activity_main.xml

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

  <fragment
    android:id="@+id/main_land"
    android:name="com.jayway.rotationcrashworkaround.MainLandscapeFragment"
    android:layout_width="0dp"
    android:layout_height="0dp" />

  <fragment
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main_portrait"
    android:name="com.jayway.rotationcrashworkaround.MainPortraitFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

</FrameLayout>

layout-land/activity_main.xml

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

 <fragment
  android:id="@+id/main_portrait"
  android:name="com.jayway.rotationcrashworkaround.MainPortraitFragment"
  android:layout_width="0dp"
  android:layout_height="0dp" />

 <fragment
  android:id="@+id/main_landscape"
  android:name="com.jayway.rotationcrashworkaround.MainLandscapeFragment"
  android:layout_width="match_parent"
  android:layout_height="match_parent" />

</FrameLayout>

Voila, the crash was no more! I admit this is in no way an optimal solution to the problem but it might be preferable to a crash. If you implement this workaround be aware that the “invisible” fragment might cause unexpected issues since it will go through its lifecycle just like the visible one. If anyone has a better solution to the problem, I’m all ears!

My sample project containing all code can be found here: https://github.com/hannesgruber/rotationcrashworkaround

The extra fragments are commented out so that you can reproduce the crash (open app, show dialog from overflow menu in actionbar, rotate). To see that the workaround is indeed solving the crash, just uncomment, rebuild and redo the reproduction steps!

This Post Has 6 Comments

  1. Hello, I got this error yesterday. Thank to your code I have fixed this error. But I found a very simple method to solve this bug. It is just a bug of the framework cause by the fragment tag. So basically I don’t have to create 2 layout file. The only thing I have to do to fix this is change fragment tag into RelativeLayout tag in activity_main.xml.
    Something like this

  2. Thanks for the comment! Unfortunately your example code seems to be missing.. Perhaps you can add it in a new comment? If this can be fixed in a better way I would really like to know how =)

  3. When I write xml tag it turn into blank. So what I did is only replace fragment tag into RelativeLayout tag in layout/activity_main.xml, and it runs

    1. I cannot just use RelativeLayout instead of fragment, the view would just be empty since the Fragment (specified in the name attribute) would not be loaded. Or do I misunderstand your suggestion?

      You mean like this right?

       
        
       
      
      

Leave a Reply

Close Menu