2012-07-21 39 views
13

De acuerdo con la documentación de la API de Android, Activity.onRetainNonConfigurationInstance() ha quedado en desuso en favor de Fragment.setRetainInstance().No se puede usar Fragment.setRetainInstance() como reemplazo de Activity.onRetainNonConfigurationInstance()

Sin embargo, he corrido en dos situaciones distintas, donde no parece Fragment.setRetainInstance() para ser factible utilizar.

  1. Si el fragmento contiene una vista Web. De acuerdo con Diane Hackborne, no puede volver a utilizar un WebView en los cambios de configuración. Supongo que significa que debe permitir que el Fragmento cierre y vuelva a crear el WebView cuando la pantalla gire, y use WebView.saveState() y WebView.restoreState() para restaurar el estado de la vista web.

  2. Si el fragmento pertenece a un diseño que ya no existe después de que el cambio de configuración, cuando el FragmentManager intenta restaurar el fragmento, arrojará:

    java.lang.IllegalArgumentException: No view found for id 0x7f060091 for fragment 
    

    Esto puede ocurrir (por ejemplo) si tiene un diseño de dos fragmentos en modo horizontal, pero un diseño de un fragmento en modo vertical. Al girar de paisaje a retrato, si setRetainInstance() se establece en verdadero, ninguno de los Fragmentos se destruye, pero un fragmento ya no tiene una vista válida para volver a adjuntarse, de ahí la excepción.

lo tanto, si usted está construyendo una aplicación basada en fragmentos, y hay que conservar los datos (por ejemplo, las referencias a la ejecución de AsyncTasks) entre los cambios de configuración, y no se puede utilizar Fragment.setRetainInstance(), y no hay Fragment.onRetainNonConfigurationInstance(), ¿cuál es el mejor enfoque para tomar?

Respuesta

0

Parece que no ha habido respuestas a mi pregunta, pero aquí es lo que terminé haciendo:

  1. Para Fragmentos contiene un WebView que necesita ser restaurado, anular Fragment.onSaveInstanceState(Bundle state) y llame WebView.saveState(bundle). Luego, en Fragment.onViewCreated(View view, Bundle savedInstanceState), llame webView.restoreState(savedInstanceState) si savedInstanceState no es nulo.

  2. Para Los fragmentos que contienen vivo AsyncTasks que necesitan ser preservados, anular Fragment.onDestroy() y guardar esas tareas en mi objeto de aplicación. (Alternativamente, también se sugiere esconderlos en un static variable). Luego, en Fragment.onCreate(Bundle savedInstanceState), verifique si esas tareas no son nulas y, de ser así, restaurelas. (Lo que esto significa es dependiente de aplicación, pero en mi caso restaurar la devolución de llamada que se invoca en el Fragmento cuando el AsyncTask ultima).

No estoy seguro si esta es la mejor solución pero parece solucionar los problemas que estaba teniendo.

Aún así, me parece toda esta situación bastante confusa (diferenciando entre onSaveInstanceState(), onRetainNonConfigurationInstance() y OnDestroy(), y decidir lo que hay que salvar en cada escenario).

8

Incluso si usa Fragment.setRetainInstance(), el fragmento seguirá derribando su vista y recíclela después de un cambio de configuración. Es decir, se llamarán onDestroyView() y onCreateView() en esa secuencia. Asegúrese de invalidar referencias antiguas a WebView en onDestroyView(). No tiene que preocuparse por volver a utilizar un WebView: se recreará un nuevo WebView con el contexto correcto de Activity. Esto es algo irrelevante porque para guardar el estado de WebView, aún necesita llamar al WebView.saveState(Bundle) en Fragment.onSaveInstanceState(Bundle), y WebView.restoreState(Bundle) en Fragment.onViewCreated(Bundle). Esto solo significa que Fragment.setRetainInstance() sigue siendo compatible con el uso de WebViews.

El ejemplo que proporcionó con respecto a un contenedor de vista que ya no existe en otra orientación significa que no necesita retener ningún dato; el fragmento no se va a utilizar en absoluto después de la rotación de la pantalla.

En cualquier caso, en lugar de hacer que un solo Fragmento maneje la carga de UI y AsyncTask, puede separarlos en dos Fragmentos: el que tiene AsyncTask no necesita estar adjunto a la jerarquía de vista y puede ser configurado para ser una instancia retenida. Esto simplifica sus preocupaciones y crea una arquitectura más limpia. Cuando finaliza la AsyncTask, debe volver a llamar al fragmento de la interfaz de usuario para entregar los resultados (por ejemplo, findFragmentById/Tag, setTargetFragment, oyentes personalizados ...). El fragmento que gestiona AsyncTask necesita poder recuperar una referencia a la nueva instancia del fragmento de UI después de la rotación.

+1

Acerca de la vista de un problema que ya no existe, está en lo cierto, pero le falta el caso en que el desarrollador podría querer tener diferentes diseños para pantallas diferentes. Por ejemplo, en algunas pantallas tanto el retrato como el paisaje tendrían 2 paneles, en algunos solo el paisaje tendría 2 paneles y en algunos de ellos tendría 1 panel. Incluso si llamo a setRetainInstance (verdadero) cuando solo hay 2 paneles, y llamo setRetainInstance (falso) cuando hay uno, obtengo la misma excepción. ¿Qué se puede hacer? –

+0

@mkuech ese comentario solo dice que no se vuelva a utilizar la misma instancia de WebView en los cambios de configuración. No estamos confiando en eso; se llama a onCreateView() por lo que estamos haciendo uno nuevo cada vez. – antonyt

+0

@antonyt Y disculpas. Parece que he cruzado algunos cables entre esta y otras preguntas más. Voy a eliminar mis comentarios anteriores para evitar confusiones. – mkuech

Cuestiones relacionadas