Cómo terminar la actividad destruida

Según entiendo, una actividad destruida no es equivalente a una actividad que está terminando .

  • Terminado
    • La actividad se quita de la pila trasera .
    • Puede ser activado por el programa (por ejemplo, llamando a finish() ), o por el usuario pulsando la tecla back (que implícitamente llama a finish() ).
    • Terminar una actividad lo destruirá.
  • Destruido
    • El sistema operativo Android puede destruir una actividad invisible para recuperar la memoria. La actividad se recreará cuando el usuario vuelva a ella.
    • La actividad se destruye y se vuelve a crear cuando el usuario gira la pantalla.
    • Referencia: recreando una actividad

Entonces, ¿ cómo puedo terminar una actividad destruida ? El método finish() requiere un objeto Activity , pero si la actividad se destruye, no tengo ningún objeto Activity – no se supone que debo mantener una referencia a una actividad destruida, ¿verdad?


Caso de estudio:

Tengo una actividad a , que comienza b , que a su vez comienza c (usando Activity.startActivity() ), así que ahora la pila trasera es:

 a → b → c 

En c , el usuario rellena un formulario y presiona el botón Enviar. Se realiza una solicitud de red a un servidor remoto mediante AsyncTask . Después de completar la tarea, muestro un brindis y termino la actividad llamando a c.finish() . Perfecto.

Ahora considere este escenario:

Mientras la tarea asíncrona está en progreso, el usuario cambia a otra aplicación. Luego, el sistema operativo Android decidió destruir las 3 actividades ( a , b , c ) debido a las restricciones de memoria. Posteriormente, se completa la tarea asíncrona. Ahora, ¿cómo terminar c ?

Lo que he intentado:

  • Llamar a c.finish() :
    • No se puede, porque c se destruye.
  • Llamar b.finishActivity() :
    • No se puede, porque b es destruido.
  • Utilice Context.startActivity() con FLAG_ACTIVITY_CLEAR_TOP para elevar b a la parte superior, finalizando así c :

     // appContext is an application context, not an activity context (which I don't have) Intent intent = new Intent(appContext, B.class); // B is b's class. intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); appContext.startActivity(intent); 
    • Error, appContext.startActivity() lanza una excepción:

Android.util.AndroidRuntimeException: Llamar startActivity () desde fuera de un contexto de Activity requiere el flag FLAG_ACTIVITY_NEW_TASK. ¿Es esto realmente lo que quieres?

Edición: Aclaración: Tengo que esperar hasta que termine la tarea asíncrona y decidir si terminar c basado en la respuesta del servidor.

Android.util.AndroidRuntimeException: Llamar startActivity () desde fuera de un contexto de Activity requiere el flag FLAG_ACTIVITY_NEW_TASK. ¿Es esto realmente lo que quieres?

  • Esta excepción solía ocurrir cuando se inicia una actividad desde
    El hilo o servicio de fondo. Necesitas pasar
    FLAG_ACTIVITY_NEW_TASK bandera siempre que necesite el "lanzador"
    Tipo de comportamiento.

    • Simplemente agregue mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Para evitar esta excepción.

  • La forma en que está tratando de matar a la actividad no es recomendable, que el android manejar por sí mismo. No hay ningún significado para terminar una actividad que ya está destruida.

Ahora, ¿qué puedes hacer?

  • Si se enfrenta a un problema en la actividad de acabado cuando la aplicación no está en primer plano, lo que puede hacer es implementar una comprobación de seguridad que finalizará la actividad sólo cuando la aplicación esté en primer plano para ir a la actividad de back-stack o simplemente saltar ese paso.

  • Pienso que usted está intentando matar la actividad cuando la aplicación está en fondo. Parece un poco difícil hacerlo, pero puedes hacer uso de onUserLeaveHint para decidir cuando la aplicación va en segundo plano en orden para terminar la actividad o puedes terminar la actividad agregando finish(); En onStop() . Sólo asegúrese de que asynctask's onPost() no lo termine de nuevo en orden para evitar la excepción.

  • Echa un vistazo a android: clearTaskOnLaunch atributo y establecerlo en true.

    Google Doc dice sobre este atributo es:

    Por ejemplo, que alguien inicie la actividad P desde la pantalla de inicio y de ahí va a la actividad Q. El usuario presiona a continuación en Inicio y luego vuelve a la actividad P. Normalmente, el usuario vería la actividad Q, ya que es lo que fueron últimos Haciendo en la tarea de P. Sin embargo, si P estableció este indicador como "true", todas las actividades encima de él (Q en este caso) fueron eliminadas cuando el usuario pulsó Home y la tarea fue al fondo. Por lo tanto, el usuario sólo ve P al volver a la tarea.

    Y creo que este es el caso exacto que desea.

Espero que esto le dará alguna pista para lograr su tarea deseada.

Puede transmitir su acción desde el método onPostExecute en c y registrar un receiver difusión para recibir para esa acción en a y b. A continuación, terminar en ese método de receptor onRevice

En c , AsyncTask,

  void onPostExecute(Long result) { ---- Intent intent1 = new Intent("you custom action"); context.sendBroadcast(intent1); } 

En a y b

 registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { finish(); } },new IntentFilter("you custom action")); 

Personalmente, usaría la barra de notificación para notificar al usuario del estado de su consulta.

De esta manera, evitaría toda la cuestión de tener una actividad inacabada. Y sólo mantendría la actividad inacabada sólo si el usuario no había hecho clic en el botón de envío todavía.

En cuanto a android manual onDestroy() llamado exactamente antes de la actividad se destruye, por lo que puede llamar a terminar en ella (incluso puede detener su hilo bg antes de matar la actividad completamente).

Podemos asumir que si la actividad fue asesinada no nos interesa bg thread tampoco, y por ejemplo, si bg hilo es descargar imagen o etc que necesita ser completado – por lo que tiene que utilizar el servicio en lugar de asynctask.

No se puede terminar una actividad destruida directamente, por lo que acaba de finish() en su onCreate() (sugerido por @Labeeb P ). Así es cómo:

  1. Si la actividad ya está destruida al intentar terminarla, guarde una bandera booleana en algún lugar.

     if(activity != null) { // Activity object still valid, so finish() now. activity.finish(); } else { // Activity is destroyed, so save a flag. is_activity_pending_finish = true; } 
    • Si la bandera necesita permanecer incluso si la aplicación se destruye, utilice almacenamiento persistente, por ejemplo SharedPreferences (sugerido por @Labeeb P ).
  2. En onCreate() la actividad, compruebe el flag y call finish() .

     @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(is_activity_pending_finish) { is_activity_pending_finish = false; // Clear the flag. // This activity should have been finished, so finish it now. finish(); return; } ... } 
    • Si hay varias instancias de la misma clase de actividad, es posible que necesite algo más que un indicador booleano para identificar la instancia específica de actividad para finalizar.

Llamar finish() en onCreate() es en realidad una operación legimate, como se menciona en el doc :

… puede llamar finish() desde onCreate() para destruir la actividad. En este caso, el sistema invoca de inmediato onDestroy() sin llamar a ninguno de los otros métodos de ciclo de vida.


Otras Consideraciones:

  • Puede que no sea una buena idea terminar una actividad mientras la aplicación esté en segundo plano, especialmente si es la única actividad. Asegúrese de no confundir al usuario.
  • Para obtener una mejor experiencia del usuario, si termina una actividad mientras la aplicación está en segundo plano, quizás desee informar al usuario. Considere el uso de tostadas (bueno para avisos cortos) o notificaciones (buenas para operaciones largas que el usuario puede haber olvidado) (sugeridas por @Stephan Branczyk y @dilix ).

Por supuesto, una actividad destruida no significa necesariamente que la aplicación esté en segundo plano (podría haber otra actividad de primer plano). Sin embargo, la solución anterior (llamar finish() en onCreate() ) funciona.

Cuando el sistema intenta destruir su actividad, llama a onSaveInstanceState . Aquí puede llamar a finish() . Eso es.

Advertencia: Nunca he probado esto, así que no sé a ciencia cierta si hay problemas con la llamada finish () de onSaveInstanceState. Si intenta esto, por favor, comente y hágamelo saber cómo funciona.

  • Actividad del conmutador androide de un hilo no ui
  • Transición cuando el cambio de tema (o Activity.recreate ())
  • Cómo encontrar la actividad de primer plano actual en android
  • System.exit (0) no cierra todas mis actividades?
  • La actividad no se está reiniciando en la pestaña cambiada en android
  • El método checkSelfPermission (Context, String) no está definido para el tipo ContextCompat
  • Android - setStatusBarColor () NoSuchMethodError excepción
  • ¿Cuál es la diferencia exacta entre onAttachedToWindow y onStart
  • ¿Cómo forzar a Acivity principal a esperar a la subactividad en Android?
  • Código antes del problema setContentView
  • Establecer argumentos de fragmento de la actividad
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.