¿Cómo puedo volver a una actividad principal correctamente?

179

Tengo 2 actividades (A y B) en mi aplicación de Android y uso la intención de pasar de la actividad A a la actividad B. El uso de parent_activity está habilitado:

 <activity
        android:name=".B"
        android:label="B" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.app_name.A" />
  </activity>

También uso un tema que proporciona un botón ARRIBA.

Entonces, después de llamar a la actividad BI, puedo usar el botón ARRIBA para volver a la actividad A. El problema es que la aplicación parece volver a llamar a la función onCreate () de la actividad A y este no es el comportamiento que necesito. Necesito que la actividad A tenga el mismo aspecto que tenía antes de llamar a la actividad B.

¿Hay una manera de lograr esto?

Gracias por adelantado

EDITAR:

No escribí ningún código para iniciar la actividad B desde la actividad A. Creo que se autogenera por eclipse.

La clase B se parece a:

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_b);
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_b, menu);
    return true;
}


@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            NavUtils.navigateUpFromSameTask(this);
            return true;
    }
    return super.onOptionsItemSelected(item);
}
ashiaka
fuente
Publique su código, para iniciar la Actividad A desde B ..
user370305
Si te entiendo bien, puedes usar startActivityForResult () y devolver un resultCode o algo así.
Law Gimenez
¡Actualice su respuesta correcta etiquetada! ¡La respuesta CORRECTA proviene de LorenzCK, no del usuario ......! ¡Etiquetar esto como correcto es engañoso y hace que incluso más programadores malinterpreten la navegación en lugar de la navegación hacia atrás!
Zordid
Vaya, hay tantas respuestas incorrectas aquí, ¿podrías ayudarme a limpiar esto ...?
Zordid
@ashiaka - Respuesta correcta según se actualiza el diseño de su código.
user370305

Respuestas:

334

Declaraste la actividad A con el estándar launchModeen el manifiesto de Android. Según la documentación , eso significa lo siguiente:

El sistema siempre crea una nueva instancia de la actividad en la tarea de destino y dirige la intención a ella.

Por lo tanto, el sistema se ve obligado a recrear la actividad A (es decir, llamar onCreate) incluso si la pila de tareas se maneja correctamente.

Para solucionar este problema, debe cambiar el manifiesto, agregando el siguiente atributo a la declaración de actividad A:

android:launchMode="singleTop"

Nota: la llamada finish()(como se sugirió anteriormente como solución) solo funciona cuando está completamente seguro de que la instancia de actividad B que está terminando se encuentra encima de una instancia de actividad A. En flujos de trabajo más complejos (por ejemplo, iniciar la actividad B desde una notificación) este podría no ser el caso y debe iniciar correctamente la actividad A desde B.

LorenzCK
fuente
11
Aquí está la explicación de los documentos de Android. Los modos "estándar" y "singleTop" difieren entre sí en un solo aspecto: cada vez que hay una nueva intención para una actividad "estándar", se crea una nueva instancia de la clase para responder a esa intención Cada instancia maneja una sola intención. Del mismo modo, también se puede crear una nueva instancia de una actividad "singleTop" para manejar una nueva intención. Sin embargo, si la tarea de destino ya tiene una instancia existente de la actividad en la parte superior de su pila, esa instancia recibirá la nueva intención (en una llamada onNewIntent ()); No se crea una nueva instancia.
kpsfoo
Tenga en cuenta que de acuerdo con la documentación navigateUpFromSameTask(...) debe agregarse FLAG_ACTIVITY_CLEAR_TOPa upIntent(a través de lo navigateUpTo(...)cual debe dar como resultado el mismo comportamiento (de acuerdo con esta guía ), pero el indicador nunca se establece, y por lo tanto esta respuesta tiene sentido
Anigif
82

Respuesta actualizada: Diseño de navegación hacia arriba

Debe declarar qué actividad es la principal adecuada para cada actividad. Hacerlo permite que el sistema facilite patrones de navegación como Arriba porque el sistema puede determinar la actividad lógica principal del archivo de manifiesto.

Para eso, debe declarar su Actividad principal en la etiqueta Actividad con atributo

android:parentActivityName

Me gusta,

<!-- The main/home activity (it has no parent activity) -->
    <activity
        android:name="com.example.app_name.A" ...>
        ...
    </activity>
    <!-- A child of the main activity -->
    <activity
        android:name=".B"
        android:label="B"
        android:parentActivityName="com.example.app_name.A" >
        <!-- Parent activity meta-data to support 4.0 and lower -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.app_name.A" />
    </activity>

Con la actividad principal declarada de esta manera, puede navegar hasta el elemento primario apropiado como se muestra a continuación,

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    // Respond to the action bar's Up/Home button
    case android.R.id.home:
        NavUtils.navigateUpFromSameTask(this);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

Entonces, cuando llama a NavUtils.navigateUpFromSameTask(this);este método, finaliza la actividad actual e inicia (o reanuda) la actividad principal adecuada. Si la actividad principal de destino está en la pila posterior de la tarea, se adelanta según lo definido por FLAG_ACTIVITY_CLEAR_TOP.

Y para mostrar el botón Arriba tienes que declarar setDisplayHomeAsUpEnabled():

@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

Respuesta anterior: (Sin navegación hacia arriba, navegación hacia atrás predeterminada)

Ocurre solo si está iniciando la Actividad A nuevamente desde la Actividad B.

Utilizando startActivity().

En lugar de esto desde la Actividad A, comience la Actividad B usando startActivityForResult()y anule onActivtyResult()en la Actividad A.

Ahora en la Actividad B simplemente llame finish()al botón Arriba. Así que ahora te dirigiste a la Actividad A onActivityResult()sin crear la Actividad A nuevamente.

usuario370305
fuente
No sé dónde se llama a startActivity () en la actividad B. He publicado el código fuente de la actividad B ...
ashiaka
18
En lugar de NavUtils.navigateUpFromSameTask(this); escribir la línea de código finish().
user370305
44
Se plantea la pregunta, ¿por qué Google no menciona nada sobre finish()o startActivityForResult()en su documentación sobre Navegación ( developer.android.com/design/patterns/navigation.html )?
wired00
Esto suena como una solución laboriosa. La respuesta de @LorenzCK parece ser mucho mejor.
carmen_munich
Muchas gracias por usar NavUtils.navigateUpFromSameTask (esto). Gran plus! He estado buscando un método como este para reemplazar el acabado () que no vuelve a la actividad principal en algunas circunstancias. terminar () es esencialmente volver a la actividad anterior que no es necesariamente la actividad principal.
Hong
22

Tenía casi la misma configuración que conducía al mismo comportamiento no deseado. Para mí, esto funcionó: agregar el siguiente atributo a una actividad A en el Manifest.xmlde mi aplicación:

android:launchMode="singleTask"

Vea este artículo para más explicaciones.

androidnewbie
fuente
1
Desde mi punto de vista, la solución correcta al problema. Esto se comportará como si llamaras a finish () si la Actividad existe en la pila de tareas. Si ese no es el caso, se creará e iniciará.
Johan
55
Esta no es la forma correcta, ya que creará una nueva tarea innecesariamente cada vez, en su lugar, debe usar launchMode = "singleTop".
kpsfoo
19

Aunque es una vieja pregunta, aquí hay otra solución (en mi opinión, la más limpia y la mejor) ya que todas las respuestas anteriores no funcionaron para mí desde que conecté la Actividad B desde un widget .

public void navigateUp() {
final Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot()) {
    Log.v(logTag, "Recreate back stack");
        TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent).startActivities();
  } else {
    NavUtils.navigateUpTo(this, upIntent);
  }
}

[ https://stackoverflow.com/a/31350642/570168 ]

Pero también vea: https://speakerdeck.com/jgilfelt/this-way-up-implementing-effective-navigation-on-android

Tobias
fuente
7

Una mejor manera de lograr esto es usando dos cosas: llamar:

NavUtils.navigateUpFromSameTask(this);

Ahora, para que esto funcione, debe hacer que su archivo de manifiesto indique que la actividad A tiene una actividad principal B. La actividad principal no necesita nada. En la versión 4 y superior, obtendrá una buena flecha hacia atrás sin esfuerzo adicional (esto se puede hacer en versiones inferiores también con un pequeño código, lo pondré a continuación) Puede configurar estos datos en el manifiesto-> pestaña de la aplicación en la GUI (desplácese hacia abajo hasta el nombre de la actividad principal y póngalo a mano)

Nodo de soporte:

si desea admitir la versión inferior a la versión 4, también debe incluir metadatos. haga clic derecho en la actividad, agregue-> metadatos, nombre = android.support.PARENT_ACTIVITY y valor = your.full.activity.name

para obtener la buena flecha también en versiones inferiores:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

tenga en cuenta que necesitará la versión 7 de la biblioteca de soporte para que todo funcione, ¡pero vale la pena!

Donald
fuente
5

Lo que funcionó para mí fue agregar:

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            case android.R.id.home:
                onBackPressed();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onBackPressed() {
        finish();
    }

ay TheRelevantActivity.javaahora está funcionando como se esperaba

y sí, no olvides agregar:

getSupportActionbar.setDisplayHomeAsUpEnabled(true);en onCreate()método

Hammad Nasir
fuente
4

Lo intenté android:launchMode="singleTask", pero no ayudó. Trabajó para mí usandoandroid:launchMode="singleInstance"

Neumonía
fuente
Agregar Android: launchMode = "singleInstance" a la actividad principal me resolvió el problema
emir
4

Agregando a la respuesta de @ LorenCK, cambie

NavUtils.navigateUpFromSameTask(this);

al código a continuación si su actividad puede iniciarse desde otra actividad y esto puede convertirse en parte de la tarea iniciada por otra aplicación

Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
    TaskStackBuilder.create(this)
            .addNextIntentWithParentStack(upIntent)
            .startActivities();
} else {
    NavUtils.navigateUpTo(this, upIntent);
}

Esto iniciará una nueva tarea e iniciará la Actividad principal de su Actividad que puede definir en el Manifiesto como a continuación de la versión Min SDK <= 15

<meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value="com.example.app_name.A" />

O usando parentActivityNamesi es> 15

Sourabh
fuente
Nota: Declare parentActivityNamepara SDK> 15 o de lo contrario le dará algunos bloqueos aleatorios
Sourabh
3

Tuve un problema similar al usar Android 5.0 con un mal nombre de actividad principal

<activity
        android:name=".DisplayMessageActivity"
        android:label="@string/title_activity_display_message"
        android:parentActivityName=".MainActivity" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.myfirstapp.MainActivity" />
    </activity>

Eliminé com.example.myfirstapp del nombre de la actividad principal y funcionó correctamente

Patrick Bergthold
fuente
2

Agregue a su actividad información de manifiesto con atributo

android:launchMode="singleTask"

me esta funcionando bien

Pravesh Kumar
fuente
1
El flujo completo es así @Override public boolean onOptionsItemSelected (elemento MenuItem) {switch (item.getItemId ()) {case android.R.id.home: NavUtils.navigateUpFromSameTask (this); volver verdadero; } return super.onOptionsItemSelected (item); }
Pravesh Kumar
Agregue a su manifiesto <activity android: name = ". MainActivity" android: label = "@ string / title_activity_main"> </activity> <activity android: name = ". CreateEventActivity" android: label = "@ string / title_activity_create_event" android : launchMode = "singleTask" android: parentActivityName = ". MainActivity"> <meta-data android: name = "android.support.PARENT_ACTIVITY" android: value = ". MainActivity" /> </activity>
Pravesh Kumar
2

En clase Java: -

    toolbar = (Toolbar) findViewById(R.id.apptool_bar);
    setSupportActionBar(toolbar);

    getSupportActionBar().setTitle("Snapdeal");

    getSupportActionBar().setHomeButtonEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

En manifiesto: -

<activity
            android:name=".SubActivity"
            android:label="@string/title_activity_sub"
            android:theme="@style/AppTheme" >
            <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".MainActivity"></meta-data>
    </activity>

Te ayudará

Kasthuri Shravankumar
fuente
1
    @Override
public boolean onOptionsItemSelected(MenuItem item) {
   switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
    case android.R.id.home:
        finish();
        return true;
}
return super.onOptionsItemSelected(item);

como una prensa de retroceso

Dan Alboteanu
fuente
1

prueba esto:

Intent intent;
@Override
public void onCreate(Bundle savedInstanceState) {
    intent = getIntent();   
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_b);
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_b, menu);
    return true;
}  

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            NavUtils.navigateUpTo(this,intent);
            return true;
    }
    return super.onOptionsItemSelected(item);
}
Luis Valadez
fuente
0

Entrando en mi manifiesto y agregando android:launchMode="singleTop" a la actividad me sirvió.

Esto resolvió mi problema específicamente porque no quería que Android creara una nueva instancia de la actividad anterior después de presionar el botón Up presionar botón en la barra de herramientas; en cambio, quería usar la instancia existente de la actividad anterior cuando subía la jerarquía de navegación.

Referencia: android: launchMode

momia
fuente