2011-08-23 11 views
19

Usando androide-support-v4.jar y FragmentActivity (no hay fragmentos en este punto)no LoaderCallbacks.onLoadFinished llamados si cambio de orientación que sucede durante la ejecución AsyncTaskLoader

tengo una AsyncTaskLoader que comienzo a la carga y a continuación, cambiar el mientras que la orientación el hilo de fondo aún se está ejecutando. En mis registros veo que las respuestas vienen a las solicitudes de fondo. Las respuestas se completan y espero que onLoadFinished() sea llamado, pero nunca lo es.

Como medio de solución de problemas, en el Manifiesto, si configuro android: configChanges = "orientation" onLoadFinished() se llama como se esperaba.

Mi actividad implementa las devoluciones de llamadas del cargador. En la fuente de LoaderManager.initLoader() veo que si el cargador ya existe, la nueva devolución de llamada se establece en la clase de objeto interno LoaderInfo, pero no veo dónde se llama de nuevo Loader.registerListener(). registerListener solo parece invocarse cuando se llama a LoaderManagerImpl.createAndInstallLoader().

Sospecho que, dado que la actividad se destruye y recrea en el cambio de orientación, y dado que es el oyente de las devoluciones de llamada, la nueva actividad no se registra para notificarse.

¿Alguien puede confirmar mi comprensión y cuál es la solución para que se llame a onLoadFinished después de cambiar la orientación?

+1

Como otro paso de solución de problemas agregué un Fragmento de trabajador sin UI y setRetainInstance en verdadero. El Fragmento implementa los LoaderCallbacks. El Fragmento se retiene entre los cambios de orientación, pero no se llama a su OnLoadFinished() después del cambio de orientación. – Daddyboy

+7

¿A dónde llamas 'initLoader()'? Asegúrese de que esté en 'onCreate()'. Por cierto, puede usar 'LoaderManager.enableDebugLogging (true)' para obtener información de depuración sobre el ciclo de vida del cargador (en logcat). –

Respuesta

34

Nikolay identificó el problema - Gracias.

Estaba llamando a initLoader fron onResume(). La documentación Android afirma:

"Por lo general, inicializar un cargador dentro onCreate de la actividad() método, o dentro método del fragmento onActivityCreated()".

Lea "normalmente" como un poco más enfático que cuando se trata de cambiar la configuración del ciclo de vida.

Moví mi llamada de initLoader a onCreate() y eso resolvió mi problema.

Creo que la razón es que en FragmentActivity.onCreate() se extrae una colección de LoaderManagers de LastNonConfigurationInstance y en FragmentActivity.onStart() hay algunos trabajos de inicio con respecto a Loaders y LoaderManagers. Las cosas ya están en proceso en el momento en que se llama a Resume(). Cuando el cargador necesita crear instancias por primera vez, todavía funciona llamar a llamar a initLoader desde fuera onCreate().

+2

Gracias por resumir esto aquí, utilicé su respuesta para la implementación de fragmentos. ¡Ayudó mucho! Además, gracias Nikolay por la información. Sorprendentemente útiles chicos! –

+1

Tuve el mismo problema. Pero mover el iniciador a onActivityCreated() no funcionó para mí. ¡Pero moverlo a onCreate() sí! No estoy seguro de por qué es eso ... ¡Gracias por una buena respuesta que ayudó mucho! – Gober

+0

También enfrenté el mismo problema. Este escenario está resuelto. Pero cuando el cargador está en progreso si el usuario bloquea el teléfono y entra en actividad, no se llama a onLoadFinished. – Meher

2

En realidad, no es la llamada a initLoader() en onCreate() que lo está arreglando. Es la llamada al getLoaderManager(). En resumen, lo que sucede es que cuando una actividad se reinicia, ya conoce los cargadores. Se trata de reiniciarlos cuando su actividad impacta onStart(), pero luego se golpea este código en FragmentHostCallback.doLoaderStart() *:

void doLoaderStart() { 
    if (mLoadersStarted) { 
     return; 
    } 
    mLoadersStarted = true; 

    if (mLoaderManager != null) { 
     mLoaderManager.doStart(); 
    } else if (!mCheckedForLoaderManager) { 
     mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false); 
     // WTF: Why aren't we calling doStart() here?! 
    } 
    mCheckedForLoaderManager = true; 
} 

Desde getLoaderManager no se llamaba todavía(), mLoaderManager es nulo. Por lo tanto, omite la primera condición y la llamada al mLoaderManager.doStart().

Puede probar esto simplemente llamando a getLoaderManager() en onCreate(). No necesita llamar a los cargadores init/restart allí.

Esto realmente me parece un error.

* Esta es la ruta de código, incluso si no está utilizando fragmentos, por lo que no se confunda con eso.

Cuestiones relacionadas