2012-03-05 14 views
14

Tengo Actividad que inicia AsyncTask. La actividad puede mostrarse en orientación Vertical u Horizontal. Cuando se cambia la orientación, la actividad se destruye y se recrea. La tarea continúa funcionando sin importar cuántas veces se cambie la orientación. También devuelve los resultados a la actividad con éxito (de acuerdo con la respuesta de CommonsWare aquí http://goo.gl/WF1yW).¿Se está destruyendo la actividad porque cambió la orientación o porque la aplicación se está cerrando?

Lo que quiero lograr es: cuando la actividad se destruye porque la aplicación se está cerrando - la tarea debe cancelarse. Sin embargo, cuando la actividad se destruye debido a un cambio de orientación , la tarea NO se debe cancelar.

Básicamente la pregunta es cómo distinguir entre los dos casos: la aplicación está cerrando/cambio de orientación. En ambos casos se llama al método onDestroy() y no hay una manera fácil de comprobar algo como esChangingOrientation() ...

P.S. También puedo considerar un enfoque totalmente diferente si es necesario.

Respuesta

3

En general, no quiere definir onConfigurationChanged() porque es muy difícil hacer las cosas bien. El mejor enfoque es dejar que la aplicación se mate y vuelva a crear cuando cambie la orientación.

Para facilitar la transición, puede implementar onRetainNonConfigurationInstance(). El sistema llamará a este método cuando sepa que su aplicación se reiniciará casi de inmediato. En onRetainNonConfigurationInstance(), transfiere cualquier objeto arbitrario al sistema ('esta' es una elección razonable). Luego, en su método onCreate(), llame al getLastNonConfigurationInstance() para obtener el objeto previamente guardado. Esto le permite restaurar su estado de manera rápida y fácil desde la invocación anterior. Creo que incluso los hilos en ejecución y los sockets abiertos se pueden pasar por este camino.

Consulte Save cache when rotate device para obtener más información.

+0

Gracias! Eso es casi exactamente lo que estoy haciendo. Utilizo onRetainNonConfigurationInstance() para almacenar la referencia al hilo durante el Recreación de la actividad. Es un poco desafortunado que haya dos desventajas en esto ... Lo publicaré en una nueva respuesta. – Stan

+1

¿Por qué se acepta esta respuesta? La pregunta era cómo distinguir entre el cambio de configuración y la terminación de la aplicación cuando se llama a 'onDestroy'. Y solo está diciendo cómo obtener un objeto previamente guardado. Creo que la respuesta de Mina Fawzy es más apropiada. Además, tenga en cuenta que 'onDestroy' no garantiza que se invoque. – Storix

2

Echa un vistazo aquí para una mejor comprensión del ciclo de vida de Android: http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

Puede utilizar onConfigurationChanged() para detectar los cambios de orientación en su actividad. Puede usar el método onDestroy() para determinar cuándo se va a matar su actividad.

+0

Gracias. Sin embargo, sé sobre el ciclo de vida de la actividad. Es por eso que no quiero usar el método onConfigurationChanged(). Usarlo significa que tengo que deshabilitar la destrucción y la recreación en el cambio de orientación. Sin embargo, quiero mantener el comportamiento predeterminado sobre el ciclo de vida de la actividad. – Stan

+0

Creo que puede usar 'onConfigurationChanged()' y hacer que realice su comportamiento predeterminado si llama 'super.onConfigurationChanged()' dentro de él? – triad

+0

Usted declara en el manifiesto si desea el comportamiento predeterminado o no. De la documentación: 'Tenga en cuenta que esto solo se invocará si ha seleccionado configuraciones que le gustaría manejar con el atributo configChanges en su manifiesto. Si se produce algún cambio en la configuración que no se selecciona para ser reportado por ese atributo, entonces, en lugar de informarlo, el sistema se detendrá y reiniciará la actividad ' – Stan

7

Encontré una solución algo satisfactoria, que quiero compartir.

Se llama al método onRetainNonConfigurationInstance() solo cuando se recrea la actividad. Más específicamente: Called by the system, as part of destroying an activity due to a configuration change, when it is known that a new instance will immediately be created for the new configuration.

Anulo este método y almaceno un marcando (indicando si ha sido llamado o no). Luego en onDestroy (llamado poco después) verifico esta bandera y si es falso Cancelé la tarea en segundo plano, porque la Actividad está siendo destruida para siempre. Si es verdadero, esto significa que se ha llamado a la opción de la cuenta en RetainNonConfigurationInstance(), lo que significa que la actividad se está recreando, por lo que dejo la tarea en ejecución.

Me hubiera gustado una solución mejor, pero no pude encontrar tal.Los problemas con esta solución son dos: el método es obsoleto; hay sin garantía que se llamará el método (según la documentación). En la práctica, la solución funciona para mí, así que voy a usarlo ...

+0

hey men, ¿pueden compartir un fragmento de código por lo que han hecho? – Jeongbebs

+0

¿Cómo se anula un método final? – Prof

+0

No creo que onRetainNonConfigurationInstance() sea final. ¿O te refieres a otro? – Stan

-1

Si sus objetivos de aplicaciones de nivel API 13 o más, debe establecer esta configuración en el manifest.xml

<activity 
android:configChanges="orientation|screenSize" 
... 
/> 
9

que pueda utilizar isFinishing() método, para comprobar si se va a morir o onDestroy() método llamado simplemente debido al cambio en la orientación

@Override 
protected void onDestroy() { 
    super.onDestroy(); 
    if(isFinishing()){ 
     Log.i("DEBUG", "App will Terminate "); 
    }else{ 
     Log.i("DEBUG", "Orientation changed"); 
    } 

} 
+0

onDestroy() no siempre se garantiza que se llame – Sohail

+0

su referencia, por favor –

+0

https://developer.android.com/reference/android/app/Activity.html#onDestroy() – Sohail

0

la mejor manera que he encontrado después de algunas investigaciones era crear una clase de aplicación y se basan en onTrimMemory (la actividad) método. Un problema con este enfoque: onTrimMemory() no se llama si la pantalla se agota o la pantalla se bloquea presionando el botón de encendido, así que tuve que implementar esa lógica por separado.

/** 
* When your app's process resides in the background LRU list: 
* TRIM_MEMORY_BACKGROUND 
* TRIM_MEMORY_MODERATE 
* TRIM_MEMORY_COMPLETE 
* 
* When your app's visibility changes: 
* TRIM_MEMORY_UI_HIDDEN 
*/ 
@Override 
public void onTrimMemory(final int level) { 
    super.onTrimMemory(level); 
    if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN 
      || level == ComponentCallbacks2.TRIM_MEMORY_BACKGROUND 
      || level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE 
      || level == ComponentCallbacks2.TRIM_MEMORY_MODERATE) { 

     // App went in background 

    } 
} 

El siguiente código es para detectar el bloqueo de pantalla. Implementé este código en uno de los métodos ActivityLifecycleCallbacks - onActivityStopped()

final PowerManager powerManager = (PowerManager) getAppContext().getSystemService(Context.POWER_SERVICE); 
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { 
    if (!powerManager.isScreenOn()) { 
     // Screen locked 
    } 
} else { 
    if (!powerManager.isInteractive()) { 
     // Screen locked  
    } 
} 
Cuestiones relacionadas