Replacing fragments and orientation change
android, android-2.2-froyo, backwards-compatibility, screen-orientation
Solution
Don't create the `SearchFormFragment` in XML. Instead have an empty `FrameLayout` which you populate in `Activity.onCreate()` without adding it to the back stack. This way the `Activity` will keep the current `Fragment` instead of trying to add the one specified in XML.
Also, using `AsyncLoader` may be a better approach, see http://code.google.com/p/android/issues/detail?id=14944
Problem
I'm developing an Android application targeting 2.x and 3.0 devices and thus I'm using the compatibilty API. I'm testing on Android 2.0. I'm trying to replace a displayed fragment with another one (search form with search results) and I'm experiencing a crash on orientation change when the second (results) fragment is displayed. Basically, I have an activity, that includes a fragment defined in layout xml as ``` <fragment class="org.prevoz.android.search.SearchFormFragment" android:id = "@+id/search_form_fragment" android:layout_width = "fill_parent" android:layout_height = "fill_parent" /> ``` The first fragment (SearchFormFragment) is displayed as a default. When user taps a "search" button, I replace the SearchFormFragment with SearchResultsFragment, which runs an AsyncTask (that's why I want to retain it) with ``` // Show the search results fragment SearchResultsFragment newSearch = new SearchResultsFragment(from, to, when); newSearch.setRetainInstance(true); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out); transaction.replace(R.id.search_form_fragment, newSearch); transaction.addToBackStack(null); transaction.commit(); ``` However, when the SearchFormFragment is displayed and orientation is changed, my application crashes with ``` ERROR/AndroidRuntime(334): FATAL EXCEPTION: main ERROR/AndroidRuntime(334): java.lang.RuntimeException: Unable to start activity ComponentInfo{org.prevoz.android/org.prevoz.android.search.MainActivity}: android.view.InflateException: Binary XML file line #13: Error inflating class fragment ERROR/AndroidRuntime(334): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663) ERROR/AndroidRuntime(334): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679) ERROR/AndroidRuntime(334): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3815) ERROR/AndroidRuntime(334): at android.app.ActivityThread.access$2400(ActivityThread.java:125) ERROR/AndroidRuntime(334): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2037) ERROR/AndroidRuntime(334): at android.os.Handler.dispatchMessage(Handler.java:99) ERROR/AndroidRuntime(334): at android.os.Looper.loop(Looper.java:123) ERROR/AndroidRuntime(334): at android.app.ActivityThread.main(ActivityThread.java:4627) ERROR/AndroidRuntime(334): at java.lang.reflect.Method.invokeNative(Native Method) ERROR/AndroidRuntime(334): at java.lang.reflect.Method.invoke(Method.java:521) ERROR/AndroidRuntime(334): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) ERROR/AndroidRuntime(334): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) ERROR/AndroidRuntime(334): at dalvik.system.NativeStart.main(Native Method) ERROR/AndroidRuntime(334): Caused by: android.view.InflateException: Binary XML file line #13: Error inflating class fragment ERROR/AndroidRuntime(334): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:582) ERROR/AndroidRuntime(334): at android.view.LayoutInflater.rInflate(LayoutInflater.java:618) ERROR/AndroidRuntime(334): at android.view.LayoutInflater.inflate(LayoutInflater.java:407) ERROR/AndroidRuntime(334): at android.view.LayoutInflater.inflate(LayoutInflater.java:320) ERROR/AndroidRuntime(334): at android.view.LayoutInflater.inflate(LayoutInflater.java:276) ERROR/AndroidRuntime(334): at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:198) ERROR/AndroidRuntime(334): at android.app.Activity.setContentView(Activity.java:1647) ERROR/AndroidRuntime(334): at org.prevoz.android.search.MainActivity.onCreate(MainActivity.java:40) ERROR/AndroidRuntime(334): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) ERROR/AndroidRuntime(334): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627) ERROR/AndroidRuntime(334): ... 12 more ERROR/AndroidRuntime(334): Caused by: java.lang.IllegalStateException: Fragment org.prevoz.android.search.SearchFormFragment did not create a view. ERROR/AndroidRuntime(334): at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:281) ERROR/AndroidRuntime(334): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:558) ERROR/AndroidRuntime(334): ... 21 more WARN/ActivityManager(59): Force finishing activity org.prevoz.android/.search.MainActivity ``` The relevant onCreateView code from SearchFormFragment does get called and I return a valid view: ``` @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View newView = inflater.inflate(R.layout.search_form_frag, container, false); return newView; } ``` The crash only happens if the SearchResultsFragment is shown, the change works fine if the default SearchFormFragment is displayed. So how do I retain the second fragment state through the orientation change? The documentation on API and state changes is really lacking.