Saltar al contenido

La aplicación se reinicia en lugar de reanudarse

Este escrito fue evaluado por expertos para asegurar la exactitud de este tutorial.

Solución:

El comportamiento que está experimentando se debe a un problema que existe en algunos lanzadores de Android desde la API 1. Puede encontrar detalles sobre el error y posibles soluciones aquí: https://code.google.com/p/android/issues/ detalle? id = 2373.

Es un problema relativamente común en los dispositivos Samsung, así como en otros fabricantes que usan un lanzador / máscara personalizado. No he visto que el problema ocurriera en un lanzador de Android.

Básicamente, la aplicación no se reinicia por completo, pero su Actividad de inicio se inicia y se agrega a la parte superior de la pila de Actividad cuando el iniciador reanuda la aplicación. Puede confirmar que este es el caso haciendo clic en el botón Atrás cuando reanude la aplicación y se muestre la Actividad de inicio. Luego, debe ingresar a la actividad que esperaba que se mostrara cuando reanudara la aplicación.

La solución alternativa que elegí implementar para resolver este problema es verificar la categoría Intent.CATEGORY_LAUNCHER y la acción Intent.ACTION_MAIN en la intención que inicia la Actividad inicial. Si esos dos indicadores están presentes y la Actividad no está en la raíz de la tarea (lo que significa que la aplicación ya se estaba ejecutando), entonces llamo a finish () en la Actividad inicial. Es posible que esa solución exacta no funcione para usted, pero algo similar debería hacerlo.

Esto es lo que hago en onCreate () de la actividad inicial / de lanzamiento:

    if (!isTaskRoot()
            && getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)
            && getIntent().getAction() != null
            && getIntent().getAction().equals(Intent.ACTION_MAIN)) 

        finish();
        return;
    

Esta pregunta sigue siendo relevante en 2016. Hoy, un evaluador de control de calidad informó que una aplicación mía se reinicia en lugar de reanudar desde el lanzador de valores en Android M.

En realidad, el sistema estaba agregando la actividad iniciada a la pila de tareas actual, pero le pareció al usuario como si se hubiera producido un reinicio y hubieran perdido su trabajo. La secuencia fue:

  1. Descargar desde Play Store (o descargar apk)
  2. Iniciar la aplicación desde el cuadro de diálogo de Play Store: aparece la actividad A [task stack: A]
  3. Navegar a la actividad B [task stack: A -> B]
  4. Presione el botón ‘Inicio’
  5. Iniciar la aplicación desde el cajón de aplicaciones: ¡aparece la actividad A! [task stack: A -> B -> A] (el usuario puede presionar el botón ‘Atrás’ para acceder a la actividad ‘B’ desde aquí)

Nota: este problema no se manifiesta en los APK de depuración implementados a través de ADB, solo en los APK descargados de Play Store o de carga lateral. En los últimos casos, la intención de lanzamiento del paso 5 contenía la bandera Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT, pero no en los casos de depuración. El problema desaparece una vez que la aplicación se ha iniciado en frío desde el lanzador. Mi sospecha es que la Tarea está sembrada con un Intent mal formado (más exactamente, no estándar) que impide el comportamiento de inicio correcto hasta que la tarea se borre por completo.

Probé varios modos de inicio de actividad, pero esas configuraciones se desvían demasiado del comportamiento estándar que el usuario esperaría: reanudar la tarea en la actividad B. Consulte la siguiente definición de comportamiento esperado en la guía de Tareas y Back Stack, en la parte inferior de la página. en ‘Iniciar una tarea’:

Un filtro de intención de este tipo hace que se muestre un icono y una etiqueta para la actividad en el iniciador de la aplicación, lo que brinda a los usuarios una forma de iniciar la actividad y volver a la tarea que crea en cualquier momento después de que se haya iniciado.

Encontré que esta respuesta es relevante e inserté lo siguiente en el método ‘onCreate’ de mi actividad raíz (A) para que se reanude correctamente cuando el usuario abre la aplicación.

                    /**
     * Ensure the application resumes whatever task the user was performing the last time
     * they opened the app from the launcher. It would be preferable to configure this
     * behavior in  AndroidMananifest.xml activity settings, but those settings cause drastic
     * undesirable changes to the way the app opens: singleTask closes ALL other activities
     * in the task every time and alwaysRetainTaskState doesn't cover this case, incredibly.
     *
     * The problem happens when the user first installs and opens the app from
     * the play store or sideloaded apk (not via ADB). On this first run, if the user opens
     * activity B from activity A, presses 'home' and then navigates back to the app via the
     * launcher, they'd expect to see activity B. Instead they're shown activity A.
     *
     * The best solution is to close this activity if it isn't the task root.
     *
     */

    if (!isTaskRoot()) 
        finish();
        return;
    

ACTUALIZACIÓN: movió esta solución de analizar indicadores de intención a consultar si la actividad está en la raíz de la tarea directamente. Los indicadores de intención son difíciles de predecir y probar con todas las diferentes formas que existen para abrir una actividad PRINCIPAL (iniciar desde casa, iniciar desde el botón ‘arriba’, iniciar desde Play Store, etc.)

¡Ajá! (tldr; vea las declaraciones en negrita en la parte inferior)

Encontré el problema … creo.

Entonces, comenzaré con una suposición. Cuando presiona el lanzador, inicia el valor predeterminado Activity o, si un Task iniciado por un lanzamiento anterior está abierto, lo trae al frente. Dicho de otra manera: si en cualquier etapa de su navegación crea un nuevo Task y finish el anterior, el lanzador ya no reanudará su aplicación.

Si esa suposición es true, Estoy bastante seguro de que debería ser un error, dado que cada Task ¿Está en el mismo proceso y es un candidato para currículum tan válido como el primero creado?

Entonces, mi problema se solucionó eliminando estas banderas de un par de Intents:

i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK );

Si bien es bastante obvio FLAG_ACTIVITY_NEW_TASK crea un nuevo Task, No me di cuenta de que la suposición anterior estaba en vigor. Lo consideré un culpable y lo eliminé para probarlo y todavía tenía un problema, así que lo descarté. Sin embargo, todavía tenía las siguientes condiciones:

i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)

Mi pantalla de bienvenida estaba iniciando el “principal” Activity en mi aplicación usando la bandera anterior. Después de todo, si hubiera “reiniciado” mi aplicación y el Activity todavía se estaba ejecutando, preferiría preservar su información de estado.

Notarás que en la documentación no se menciona el inicio de una nueva Task:

Si se establece, y la actividad que se está lanzando ya se está ejecutando en la tarea actual, entonces, en lugar de lanzar una nueva instancia de esa actividad, todas las demás actividades encima de ella se cerrarán y este Intent se entregará al (ahora en arriba) la actividad anterior como una nueva intención.

Por ejemplo, considere una tarea que consta de las actividades: A, B, C, D. Si D llama a startActivity () con un Intent que se resuelve en el componente de la actividad B, entonces C y D se terminarán y B recibirá el Intent dado. , lo que da como resultado que la pila ahora sea: A, B.

La instancia actualmente en ejecución de la actividad B en el ejemplo anterior recibirá la nueva intención que está comenzando aquí en su método onNewIntent (), o se terminará y reiniciará con la nueva intención. Si ha declarado que su modo de lanzamiento es “múltiple” (el predeterminado) y no ha configurado FLAG_ACTIVITY_SINGLE_TOP con la misma intención, entonces se terminará y se volverá a crear; para todos los demás modos de lanzamiento o si se establece FLAG_ACTIVITY_SINGLE_TOP, este Intent se entregará al onNewIntent () de la instancia actual.

Este modo de ejecución también se puede usar con buenos resultados junto con FLAG_ACTIVITY_NEW_TASK: si se usa para iniciar la actividad raíz de una tarea, traerá cualquier instancia de esa tarea que se esté ejecutando actualmente en primer plano y luego la borrará a su estado raíz. Esto es especialmente útil, por ejemplo, al iniciar una actividad desde el administrador de notificaciones.

Entonces, tuve la situación como se describe a continuación:

  • A lanzado B con FLAG_ACTIVITY_CLEAR_TOP, A acabados.
  • B desea reiniciar un servicio, por lo que envía al usuario a A que tiene la lógica de reinicio del servicio y la interfaz de usuario (sin banderas).
  • A lanza B con FLAG_ACTIVITY_CLEAR_TOP, A acabados.

En esta etapa el segundo FLAG_ACTIVITY_CLEAR_TOP la bandera está reiniciando B que está en la pila de tareas. Supongo que esto debe destruir el Task y comenzar uno nuevo, causando mi problema, que es una situación muy difícil de detectar si me preguntas.

Entonces, si todas mis suposiciones son correctas:

  • los Launcher solo reanuda la tarea creada inicialmente
  • FLAG_ACTIVITY_CLEAR_TOP lo hará, si se reinicia el único restante Activity, también recrear un nuevo Task

Aquí puedes ver las comentarios y valoraciones de los usuarios

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *