Regresando de una actividad usando navigateUpFromSameTask ()
Tengo dos actividades, A y B. Cuando se inicia la actividad A, accede a la Intent
pasada a ella (porque el Bundle
es null
, como debería ser la primera vez) y muestra la información en consecuencia:
CustInfo m_custInfo; ... protected void onCreate(Bundle savedInstanceState) { ... Bundle bundle = (savedInstanceState == null) ? getIntent().getExtras() : savedInstanceState; m_custInfo = (CustInfo) m_bundle.getSerializable("CustInfo"); if (m_custInfo != null ... }
Esto funciona bien la primera vez. Los controles EditText
y ListView
se rellenan correctamente.
- ¿La instancia de aplicación siempre se crea antes de cualquier actividad?
- Enviar datos del servicio a la actividad Android
- La instancia de actividad sigue existiendo incluso después de que onDestroy () se llame
- ¿Por qué "onPause" no se llama en la siguiente situación?
- Color de fondo ondulado de Android
Ahora, cuando se hace clic en un elemento de la lista, se inicia la actividad B para mostrar los detalles:
m_custInfo = m_arrCustomers.get(pos); Intent intent = new Intent(A.this, B.class); intent.putExtra("CustInfo", m_custInfo); // CustInfo is serializable // printing this intent, it shows to have extras and no flags startActivityForResult(intent, 1);
Justo antes de iniciar la actividad B, el framework llama a A sobreescrito onSaveInstanceState()
:
protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putSerializable("CustInfo", m_custInfo); }
En la actividad B, cuando se presiona el botón Arriba en la barra de acción, quiero volver a la actividad A y tenerla en el mismo estado en que estaba antes:
public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { Intent intent = NavUtils.getParentActivityIntent(this); // printing this intent, it shows to have flags but no extras NavUtils.navigateUpFromSameTask(this); // tried finish() here but that created an even bigger mess return true; } ... }
Aquí reside el problema, cuando en onCreate()
de la actividad A la segunda vez, el parámetro Bundle
es null
y getExtras()
devuelve null
. Desde que se llamó onSaveInstanceState()
, habría esperado que el parámetro Bundle
fuera no null
.
He leído sobre este tema en otros sitios web, he probado las sugerencias, pero nada funciona.
- Actualizar actividad si se cambia la preferencia
- La aplicación o la actividad lleva tiempo para cargarse algunas veces
- Inicie la aplicación de Android con actividad específica
- OnStop () no se llama?
- Establecer dinámicamente el color del tema
- ¿Cómo iniciar una actividad diferente usando la caja de conmutación en el elemento de menú?
- Cómo terminar varias actividades al salir del android
- Cómo configurar la orientación ContentPage en Xamarin.Forms
Si desea que su aplicación reaccione de esta manera, debe declarar el modo de inicio de su actividad A como:
android:launchMode="singleTop"
En su AndroidManifest.xml.
De lo contrario, Android utiliza el modo de inicio estándar, lo que significa
"El sistema siempre crea una nueva instancia de la actividad en la tarea de destino"
Y su actividad se ha recreado (consulte la documentación de Android ).
Con singleTop el sistema vuelve a su actividad existente (con el extra original), si está en la parte superior de la pila trasera de la tarea. No es necesario implementar onSaveInstanceState en esta situación.
SavedInstanceState es nulo en su caso, porque su actividad no estaba siendo cerrada por el sistema operativo anteriormente.
Aviso (gracias, desarrollador android por señalar esto ) :
Si bien esta es una solución a la pregunta, no funcionará si la actividad a la que se devuelve no está en la parte superior de la pila trasera. Considere el caso de la actividad A iniciando B, que está iniciando C, y la actividad principal de C está configurada para ser A. Si llama a NavigateUpFromSameTask()
desde C, la actividad se recreará, porque A no está en la parte superior de la pila.
En este caso uno puede usar este pedazo de código en su lugar:
Intent intent = NavUtils.getParentActivityIntent(this); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP); NavUtils.navigateUpTo(this, intent);
Esto sucede porque NavUtils.navigateUpFromSameTask()
básicamente sólo llama startActivity(intentForActivityA)
. Si la actividad A usa el android:launchMode="standard"
defecto android:launchMode="standard"
entonces se crea una nueva instancia de la actividad y no se usa el estado guardado. Hay tres maneras de arreglar esto, con varias ventajas y desventajas.
Opción 1
Anule getParentActivityIntent () en la actividad B y especifique los extras adecuados necesarios para la actividad A:
@Override public Intent getParentActivityIntent() { Intent intent = super.getParentActivityIntent(); intent.putSerializable("CustInfo", m_custInfo); return intent; }
Nota: Si está utilizando ActionBarActivity y la barra de herramientas de la biblioteca de soporte, deberá sustituir getSupportParentActivityIntent () .
Creo que esta es la solución más elegante ya que funciona independientemente de cómo el usuario navegó a la actividad B. Las dos opciones que se enumeran a continuación no funcionan correctamente si el usuario navega directamente a la actividad B sin pasar por la actividad A, por ejemplo, si la actividad B se inicia desde un controlador de notificación o URL. Creo que este escenario es la razón por la "arriba" de navegación API es complicado y no simplemente actuar como un mudo botón de nuevo.
Un inconveniente de esta solución es que se utiliza la animación de transición de inicio de una actividad nueva estándar en lugar de la animación de actividad de retorno a anterior.
opcion 2
Interceptar el botón de arriba y tratarlo como un botón de mudo de nuevo por sobreescribir onNavigateUp () :
@Override public boolean onNavigateUp() { onBackPressed(); return true; }
Nota: Si está utilizando ActionBarActivity y la barra de herramientas de la biblioteca de soporte, deberá sustituir onSupportNavigateUp () .
Una ventaja de esta solución es que se utiliza la animación estándar de retorno a actividad anterior.
Opción 3
Como sugiere yonojoy, defina android:launchMode="singleTop"
en la actividad A. Vea su respuesta para más detalles. Tenga en cuenta que singleTop
no es apropiado para todas las aplicaciones. Tendrás que probarlo y / o pasar algún tiempo leyendo la documentación para decidir por ti mismo.
En lugar de llamar a NavUtils.navigateUpFromSameTask
Puede obtener la intención de los padres y modificarla antes de navegar. Por ejemplo:
Intent intent = NavUtils.getParentActivityIntent(this); intent.putExtra("CustInfo", m_custInfo); // CustInfo is serializable NavUtils.navigateUpTo(this, intent);
Esto se comportará exactamente igual que NavUtils.navigateUpFromSameTask
pero le permitirá agregar algunas propiedades adicionales a la intención. Puedes echar un vistazo al código de NavUtils.navigateUpFromSameTask
es muy simple.
public static void navigateUpFromSameTask(Activity sourceActivity) { Intent upIntent = getParentActivityIntent(sourceActivity); if (upIntent == null) { throw new IllegalArgumentException("Activity " + sourceActivity.getClass().getSimpleName() + " does not have a parent activity name specified." + " (Did you forget to add the android.support.PARENT_ACTIVITY <meta-data> " + " element in your manifest?)"); } navigateUpTo(sourceActivity, upIntent); }
Hacer la actividad de los padres SINGLE_TOP puede funcionar para algunas aplicaciones sencillas, pero ¿y si esta actividad no se inició directamente desde su padre? O puede legítimamente querer que el padre exista en varios lugares en la pila trasera.
Mencionas:
En la actividad B, cuando se pulsa el botón Arriba en la barra de acción, quiero volver a la actividad A y tenerla en el mismo estado en que estaba antes.
Si el contenido de la Actividad A reside en un Fragmento, entonces llame a setRetainInstance (true) en el onCreate () del Fragmento.
A continuación, la instancia de Fragmento se mantendrá en Recreación de actividad.
- ¿Cómo puedo leer un archivo de texto desde la tarjeta SD en Android?
- El mensaje EditText setError no se borra después de la entrada