Sustitución de fragmentos y cambio de orientación

Estoy desarrollando una aplicación de Android orientada a dispositivos 2.x y 3.0 y, por lo tanto, estoy utilizando la API de compatibilidad. Estoy probando en Android 2.0.

Estoy tratando de reemplazar un fragmento visualizado por otro (formulario de búsqueda con resultados de búsqueda) y estoy experimentando un bloqueo en el cambio de orientación cuando se muestra el segundo fragmento (resultados).

Básicamente, tengo una actividad, que incluye un fragmento definido en 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" /> 

El primer fragmento (SearchFormFragment) se muestra como predeterminado. Cuando el usuario pulsa un botón de "búsqueda", reemplazo el SearchFormFragment con SearchResultsFragment, que ejecuta un AsyncTask (es por eso que quiero conservarlo) con

  // 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(); 

Sin embargo, cuando se muestra el SearchFormFragment y se cambia la orientación, mi aplicación se bloquea con

 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 

El código onCreateView relevante de SearchFormFragment se llama y devuelvo una vista válida:

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View newView = inflater.inflate(R.layout.search_form_frag, container, false); return newView; } 

El bloqueo sólo ocurre si se muestra SearchResultsFragment, el cambio funciona bien si se muestra el SearchFormFragment predeterminado.

Entonces, ¿cómo puedo retener el estado del segundo fragmento a través del cambio de orientación? La documentación sobre API y cambios de estado es realmente falta.

No cree el SearchFormFragment en XML. En su lugar, tiene un FrameLayout vacío que se rellena en Activity.onCreate() sin agregarlo a la pila posterior. De esta manera, la Activity mantendrá el Fragment actual en lugar de intentar agregar el especificado en XML.

Además, utilizar AsyncLoader puede ser un enfoque mejor, consulte http://code.google.com/p/android/issues/detail?id=14944

Después de luchar con esto durante muchas horas, finalmente lo conseguí. El problema no está en la configuración o en la forma en que llamamos Fragment clase en absoluto. Tiene que ver con un mensaje equivocado que se muestra en la pantalla. Si tiene un cheque para un contenedor que es nulo en su onCreateView () en su clase Ftagment, obtendrá que "no se puede inflar fragmento" mensaje, en lugar de contenedor es nulo mensaje. Por lo tanto, no busque el contenedor nulo en su onCreateView (). Así que asegúrese de que su onCreateView () se ve así:

  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return(inflater.inflate(R.layout.title_layout, container, false)); } 

Y NO así:

  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if(container == null){ return null; } return(inflater.inflate(R.layout.title_layout, container, false)); } 

Por razones de referencia: Pudimos resolver un problema muy similar añadiendo un android:id a nuestro fragmento creado en XML.

Esta condición previa muy importante para soportar la rotación libre de fallos sólo se menciona como una nota secundaria en la documentación :

Nota: cada fragmento requiere un identificador único que el sistema puede utilizar para restaurar el fragmento si se reinicia la actividad (y que puede utilizar para capturar el fragmento para realizar transacciones, como quitarlo).

  • Cómo evitar que las vistas personalizadas pierdan estado a través de los cambios de orientación de la pantalla
  • ¿Cómo forzar un cambio de orientación en una prueba de instrumentación de Android?
  • Mi aplicación Android gira aunque la rotación de la pantalla esté desactivada en el sistema operativo. ¿Cómo puedo arreglar esto?
  • ¿Cómo hacer que mi aplicación se vea igual en todos los dispositivos?
  • Androide. Bloquear la orientación de la pantalla para todas las actividades
  • Fragmentos restauran el estado en la orientación cambiada
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.