Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Al cerrar la sesión, desactive la pila del historial de actividades, evitando que el botón "volver" abra las actividades activadas

Todas las actividades de mi aplicación requieren que un usuario se registre para verlo. Los usuarios pueden desconectarse de casi cualquier actividad. Este es un requisito de la aplicación. En cualquier momento si el usuario se desconecta, quiero enviar al usuario a la Activity inicio de sesión. En este punto, quiero que esta actividad esté en la parte inferior de la pila de historiales, de modo que al presionar el botón "volver" se devuelve al usuario a la pantalla de inicio de Android.

He visto esta pregunta hecha a unos pocos lugares diferentes, todos respondieron con respuestas similares (que describo aquí), pero quiero plantearlo aquí para recopilar comentarios.

He intentado abrir la actividad de inicio de sesión estableciendo sus indicadores de Intent en FLAG_ACTIVITY_CLEAR_TOP que parece hacer lo que se describe en la documentación, pero no alcanza mi objetivo de colocar la actividad de inicio de sesión en la parte inferior de la pila del historial e impedir que el usuario Navegando de nuevo a las actividades previamente-vistas registradas-en. También intenté usar android:launchMode="singleTop" para la actividad de inicio de sesión en el manifiesto, pero esto no logra mi meta tampoco (y parece no tener ningún efecto de todos modos).

Creo que necesito borrar la pila de historial, o terminar todas las actividades previamente abiertas.

Una opción es que el registro de onCreate cada actividad onCreate registrado en el estado, y finish() si no está conectado. No me gusta esta opción, ya que el botón de retroceso seguirá estando disponible para su uso, navegar hacia atrás como actividades cerca de sí mismos.

La siguiente opción es mantener una LinkedList de referencias a todas las actividades abiertas que esté estaticamente accesible desde cualquier lugar (quizás usando referencias débiles). Al terminar de sesión accederé a esta lista e iteraré sobre todas las actividades previamente abiertas, invocando finish() en cada una de ellas. Probablemente empezaré a implementar este método pronto.

Prefiero usar algún truco de la bandera de Intent para lograr esto, sin embargo. Sería más que feliz encontrar que puedo cumplir con los requisitos de mi aplicación sin tener que utilizar cualquiera de los dos métodos que he descrito anteriormente.

¿Hay una manera de lograr esto usando Intent o configuración de manifiesto, o es mi segunda opción, el mantenimiento de un LinkedList de actividades abiertas la mejor opción? O hay otra opción que estoy completamente con vistas?

16 Solutions collect form web for “Al cerrar la sesión, desactive la pila del historial de actividades, evitando que el botón "volver" abra las actividades activadas”

Puedo sugerirle otro enfoque IMHO más robusto. Básicamente, es necesario transmitir un mensaje de cierre de sesión a todas las Actividades que necesiten permanecer en estado de inicio de sesión. Así que puedes usar el sendBroadcast e instalar un BroadcastReceiver en todas tus Actvities. Algo como esto:

 /** on your logout method:**/ Intent broadcastIntent = new Intent(); broadcastIntent.setAction("com.package.ACTION_LOGOUT"); sendBroadcast(broadcastIntent); 

El receptor (actividad asegurada):

 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /**snip **/ IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("com.package.ACTION_LOGOUT"); registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d("onReceive","Logout in progress"); //At this point you should start the login activity and finish this one finish(); } }, intentFilter); //** snip **// } 

Parece un rito de paso que un nuevo programador de Android pasa un día investigando este problema y la lectura de todos estos subprocesos StackOverflow. Ahora estoy recién iniciado y dejo aquí rastro de mi humilde experiencia para ayudar a un futuro peregrino.

En primer lugar, no hay manera obvia o inmediata de hacer esto por mi investigación (as of September 2012). Se podría pensar que podría startActivity(new Intent(this, LoginActivity.class), CLEAR_STACK) simple startActivity(new Intent(this, LoginActivity.class), CLEAR_STACK) pero no .

Puedes hacer startActivity(new Intent(this, LoginActivity.class)) con FLAG_ACTIVITY_CLEAR_TOP y esto hará que el framework busque en la pila, encuentre tu instancia original más temprana de LoginActivity, lo recree y despeje el resto de la pila (hacia arriba) . Y puesto que Login es presumiblemente en la parte inferior de la pila, ahora tiene una pila vacía y el botón Atrás sólo sale de la aplicación.

PERO – esto sólo funciona si ha dejado anteriormente la instancia original de LoginActivity viva en la base de su pila. Si, al igual que muchos programadores, ha elegido finish() que LoginActivity una vez que el usuario ha iniciado sesión correctamente, ya no está en la base de la pila y la semántica FLAG_ACTIVITY_CLEAR_TOP no se aplica … termina creando una nueva LoginActivity en Parte superior de la pila existente. Que es casi seguro que NO lo que quieres (comportamiento extraño donde el usuario puede "volver" su camino de entrada en una pantalla anterior).

Así que si has finish() previamente finish() 'd la LoginActivity , debes buscar algún mecanismo para despejar tu stack y luego iniciar una nueva LoginActivity . Parece que la respuesta de @doreamon en este hilo es la mejor solución (al menos para mi ojo humilde):

https://stackoverflow.com/a/9580057/614880

Sospecho firmemente que las complicadas implicaciones de si dejas LoginActivity vivo están causando mucha de esta confusión.

Buena suerte.

ACTUALIZAR

El finishAffinity() super finishAffinity() ayudará a reducir el código pero lograr el mismo. Finalizará la actividad actual, así como todas las actividades de la pila, use getActivity().finishAffinity() si está en un fragmento.

 finishAffinity(); startActivity(new Intent(mActivity, LoginActivity.class)); 

RESPUESTA ORIGINAL

Supongamos que LoginActivity -> HomeActivity -> … -> SettingsActivity llamar a signOut ():

 void signOut() { Intent intent = new Intent(this, HomeActivity.class); intent.putExtra("finish", true); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // To clean up all activities startActivity(intent); finish(); } 

HomeActivity:

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); boolean finish = getIntent().getBooleanExtra("finish", false); if (finish) { startActivity(new Intent(mContext, LoginActivity.class)); finish(); return; } initializeView(); } 

Esto funciona para mí, espero que sea útil para usted también. 🙂

Si está usando la API 11 o superior, puede probar esto: FLAG_ACTIVITY_CLEAR_TASK – parece que está tratando exactamente el problema que está teniendo. Obviamente, la multitud pre-API 11 tendría que usar alguna combinación de tener todas las actividades para comprobar un extra, como sugiere @doreamon, o alguna otra trampa.

(También tenga en cuenta: para usar esto debes pasar en FLAG_ACTIVITY_NEW_TASK )

 Intent intent = new Intent(this, LoginActivity.class); intent.putExtra("finish", true); // if you are checking for this in your other Activities intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); finish(); 

Pasé unas horas en esto también … y estoy de acuerdo en que FLAG_ACTIVITY_CLEAR_TOP suena como lo que querrías: despejar la pila entera, excepto la actividad que se está iniciando, por lo que el botón Atrás sale de la aplicación. Sin embargo, como Mike Repass mencionó, FLAG_ACTIVITY_CLEAR_TOP sólo funciona cuando la actividad que está lanzando ya está en la pila; Cuando la actividad no está allí, la bandera no hace nada.

¿Qué hacer? Ponga la actividad que se está iniciando en la pila con FLAG_ACTIVITY_NEW_TASK , lo que hace que la actividad sea el inicio de una nueva tarea en la pila de historial. A continuación, agregue el indicador FLAG_ACTIVITY_CLEAR_TOP.

Ahora, cuando FLAG_ACTIVITY_CLEAR_TOP va a encontrar la nueva actividad en la pila, estará ahí y se detendrá antes de que se borre todo lo demás.

Aquí está mi función de cierre de sesión; El parámetro Ver es el botón al que está conectada la función.

 public void onLogoutClick(final View view) { Intent i = new Intent(this, Splash.class); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(i); finish(); } 

Muchas respuestas. Puede ser éste también ayudará-

 Intent intent = new Intent(activity, SignInActivity.class) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); this.startActivity(intent); this.finish(); 

Utilice esto debe ser útil para usted. Ligeramente modificado xbakesx respuesta.

 Intent intent = new Intent(this, LoginActivity.class); if(Build.VERSION.SDK_INT >= 11) { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK); } else { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); } startActivity(intent); 

Solución aceptada no es correcta, tiene problemas como el uso de un receptor de difusión no es una buena idea para este problema. Si su actividad ya ha llamado método onDestroy (), no recibirá el receptor. La mejor solución es tener un valor booleano en sus preferencias compartidas y comprobarlo en el método onCreate () de su activty. Si no se debe llamar cuando el usuario no ha iniciado sesión, finaliza la actividad. Aquí hay código de ejemplo para eso. Tan simple y funciona para cada condición.

 protected void onResume() { super.onResume(); if (isAuthRequired()) { checkAuthStatus(); } } private void checkAuthStatus() { //check your shared pref value for login in this method if (checkIfSharedPrefLoginValueIsTrue()) { finish(); } } boolean isAuthRequired() { return true; } 

La respuesta seleccionada es inteligente y difícil. He aquí cómo lo hice:

LoginActivity es la actividad raíz de la tarea, establezca android: noHistory = "true" en Manifest.xml; Digamos que desea cerrar la sesión de SettingsActivity, puede hacerlo de la siguiente manera:

  Intent i = new Intent(SettingsActivity.this, LoginActivity.class); i.addFlags(IntentCompat.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(i); 

Aquí está la solución que me surgió en mi aplicación.

En mi LoginActivity, después de procesar correctamente un inicio de sesión, inicio el siguiente de manera diferente dependiendo del nivel de la API.

 Intent i = new Intent(this, MainActivity.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { startActivity(i); finish(); } else { startActivityForResult(i, REQUEST_LOGIN_GINGERBREAD); } 

A continuación, en el método onActivityForResult de LoginActivity:

 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB && requestCode == REQUEST_LOGIN_GINGERBREAD && resultCode == Activity.RESULT_CANCELED) { moveTaskToBack(true); } 

Finalmente, después de procesar un logout en cualquier otra Actividad:

 Intent i = new Intent(this, LoginActivity.class); i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(i); 

Cuando está en Gingerbread, lo hace si presiono el botón Atrás de MainActivity, la LoginActivity se oculta inmediatamente. En Honeycomb y más tarde, acabo de terminar el LoginActivity después de procesar un inicio de sesión y se recrea correctamente después de procesar un cierre de sesión.

Inicia tu actividad con StartActivityForResult y mientras te desconectas estableces tu resultado y según tu resultado finaliza tu actividad

 intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); startActivityForResult(intent, BACK_SCREEN); @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case BACK_SCREEN: if (resultCode == REFRESH) { setResult(REFRESH); finish(); } break; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog alertDialog = builder.create(); alertDialog .setTitle((String) getResources().getText(R.string.home)); alertDialog.setMessage((String) getResources().getText( R.string.gotoHome)); alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { setResult(REFRESH); finish(); } }); alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "No", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { } }); alertDialog.show(); return true; } else return super.onKeyDown(keyCode, event); } 

La solución @doreamon proporcionada funciona bien para todos los casos excepto uno:

Si Después de iniciar sesión, el usuario de la pantalla de inicio de sesión de matanza navegó directamente a una pantalla intermedia. Por ejemplo, en un flujo de A-> B-> C, navegue como: Inicio de sesión -> B -> C -> Presione acceso directo a casa. El uso de FLAG_ACTIVITY_CLEAR_TOP borra sólo la actividad C, ya que el Home (A) no está en el historial de pila. Presionando Atrás en una pantalla nos llevará de regreso a B.

Para hacer frente a este problema, podemos mantener una pila de actividades (Arraylist) y cuando se presiona la casa, tenemos que matar todas las actividades en esta pila.

Es posible mediante la gestión de un indicador en SharedPreferences o en la actividad de la aplicación.

Al iniciar la aplicación (en la pantalla Splash), establezca el flag = false; En el evento Logout Click simplemente establezca el flag true y en OnResume () de cada actividad, compruebe si flag es true entonces call finish ().

Funciona a las mil maravillas 🙂

Al hacer clic en Cerrar sesión puede llamar a esto

 private void GoToPreviousActivity() { setResult(REQUEST_CODE_LOGOUT); this.finish(); } 

OnActivityResult () de la actividad anterior, llame este código anterior de nuevo hasta que haya terminado todas las actividades.

Esto funcionó para mí:

  // After logout redirect user to Loing Activity Intent i = new Intent(_context, MainActivity.class); // Closing all the Activities i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); // Add new Flag to start new Activity i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Staring Login Activity _context.startActivity(i); 

Una opción es que el registro de onCreate de cada actividad esté registrado y termine () si no está conectado. No me gusta esta opción, ya que el botón de retroceso seguirá estando disponible para su uso, navegar hacia atrás como actividades cerca de sí mismos.

Lo que usted quiere hacer es llamar a logout () y finish () en sus métodos onStop () o onPause (). Esto forzará a Android a llamar a onCreate () cuando la actividad se vuelve a activar ya que no la tendrá en la pila de su actividad por más tiempo. Luego haz lo que dices, en onCreate () comprueba el estado registrado y envía a la pantalla de inicio de sesión si no has iniciado sesión.

Otra cosa que puedes hacer es comprobar el estado de sesión en onResume (), y si no has iniciado sesión, finish () y iniciar la actividad de inicio de sesión.

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.