Al cerrar sesión, borre la stack del historial de actividad, impidiendo que el botón “Atrás” abriera las actividades registradas.

Todas las actividades en mi aplicación requieren que el usuario inicie sesión para verlas. Los usuarios pueden desconectarse de casi cualquier actividad. Este es un requisito de la aplicación. En cualquier momento, si el usuario cierra la sesión, 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 stack del historial, de modo que presionar el botón “volver” devuelve al usuario a la pantalla de inicio de Android.

He visto esta pregunta en algunos lugares diferentes, todos respondidos con respuestas similares (que detallo aquí), pero quiero plantearlo aquí para recostackr comentarios.

Intenté abrir la actividad de Inicio de sesión configurando sus indicadores de Intent en FLAG_ACTIVITY_CLEAR_TOP que parece funcionar como se describe en la documentación, pero no logro mi objective de colocar la actividad de inicio de sesión en la parte inferior de la stack de historial y evitar que el usuario navegando de regreso a actividades registradas anteriormente. También intenté usar android:launchMode="singleTop" para la actividad de inicio de sesión en el manifiesto, pero tampoco cumple mi objective (y parece que no tiene ningún efecto).

Creo que necesito borrar el historial o terminar todas las actividades abiertas anteriormente.

Una opción es tener el onCreate de onCreate sesión onCreate comprobación de cada actividad, y finish() si no está conectado. No me gusta esta opción, ya que el botón Atrás estará disponible para su uso, navegando hacia atrás mientras las actividades se cierran.

La siguiente opción es mantener una LinkedList de referencias a todas las actividades abiertas que sean estáticamente accesibles desde cualquier lugar (tal vez usando referencias débiles). Al cerrar la sesión, accederé a esta lista e iteraré sobre todas las actividades abiertas anteriormente, invocando finish() en cada una. Probablemente comenzaré a implementar este método pronto.

Sin embargo, prefiero usar algún truco de bandera de Intent para lograr esto. Me encantaría descubrir que puedo cumplir con los requisitos de mi aplicación sin tener que utilizar ninguno de los dos métodos que he descrito anteriormente.

¿Hay alguna manera de lograr esto usando Intent o configuración de manifiesto, o es mi segunda opción, mantener una LinkedList de actividades abiertas la mejor opción? ¿O hay otra opción que estoy pasando por alto completamente?

    Puedo sugerirle otro enfoque en mi humilde opinión más sólida. Básicamente, debe transmitir un mensaje de cierre de sesión a todas sus Actividades que necesiten mantenerse bajo un estado de inicio de sesión. Entonces puede usar sendBroadcast e instalar un BroadcastReceiver en todas sus actvidades. 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 progtwigdor de Android pase un día investigando este problema y leyendo todos estos hilos de StackOverflow. Ahora estoy recién iniciado y dejo aquí el rastro de mi humilde experiencia para ayudar a un futuro peregrino.

    En primer lugar, no hay una forma obvia o inmediata de hacerlo por mi investigación (as of September 2012). Pensarías que podrías startActivity(new Intent(this, LoginActivity.class), CLEAR_STACK) simplemente la startActivity(new Intent(this, LoginActivity.class), CLEAR_STACK) pero no .

    PUEDE hacer startActivity(new Intent(this, LoginActivity.class)) con FLAG_ACTIVITY_CLEAR_TOP – y esto hará que el framework busque en la stack, encuentre su instancia original anterior de LoginActivity, recíclela y borre el rest de la stack (hacia arriba) . Y dado que el inicio de sesión se encuentra presumiblemente en la parte inferior de la stack, ahora tiene una stack vacía y el botón Atrás simplemente sale de la aplicación.

    PERO – esto solo funciona si dejó previamente esa instancia original de LoginActivity en la base de su stack. Si, como muchos progtwigdores, LoginActivity finish() esa LoginActivity una vez que el usuario ha iniciado sesión exitosamente, entonces ya no está en la base de la stack y la semántica de FLAG_ACTIVITY_CLEAR_TOP no se aplica … terminas creando una nueva LoginActivity en parte superior de la stack existente. Lo cual, casi con seguridad, NO es lo que quiere (comportamiento extraño en el que el usuario puede “retroceder” para salir de su inicio de sesión en una pantalla anterior).

    Entonces, si previamente ha finish() ‘la actividad de LoginActivity , necesita buscar algún mecanismo para borrar su stack y luego comenzar una nueva LoginActivity inicio de LoginActivity . Parece que la respuesta de @doreamon en este hilo es la mejor solución (al menos para mi humilde ojo):

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

    Sospecho fuertemente que las complicadas implicaciones de si deja LoginActivity vivo están causando mucha confusión.

    Buena suerte.

    ACTUALIZAR

    el finishAffinity() super finishAffinity() ayudará a reducir el código pero logrará lo mismo. Terminará la actividad actual, así como todas las actividades en la stack, usa getActivity().finishAffinity() si estás en un fragmento.

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

    RESPUESTA ORIGINAL

    Supongamos que LoginActivity -> HomeActivity -> … -> SettingsActivity call 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á utilizando API 11 o superior, puede intentar esto: FLAG_ACTIVITY_CLEAR_TASK – parece estar abordando 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 @doreamon sugiere, o algún otro truco.

    (También tenga en cuenta que para usar esto debe pasar 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 acepto que FLAG_ACTIVITY_CLEAR_TOP suena como lo que querrías: borrar toda la stack, excepto la actividad que se está iniciando, por lo que el botón Atrás sale de la aplicación. Sin embargo, como mencionó Mike Repass , FLAG_ACTIVITY_CLEAR_TOP solo funciona cuando la actividad que estás lanzando ya está en la stack; cuando la actividad no está allí, la bandera no hace nada.

    ¿Qué hacer? Ponga en marcha la actividad en la stack con FLAG_ACTIVITY_NEW_TASK , que convierte esa actividad en el inicio de una nueva tarea en la stack del historial. A continuación, agregue el indicador FLAG_ACTIVITY_CLEAR_TOP.

    Ahora, cuando FLAG_ACTIVITY_CLEAR_TOP va a buscar la nueva actividad en la stack, estará allí y se levantará antes de que todo lo demás se borre.

    Aquí está mi función de cierre de sesión; el parámetro Ver es el botón al que está asociada 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 que este también ayude-

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

    Use esto, debería ser útil para usted. Respuesta xbakesx levemente modificada.

     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); 

    La solución aceptada no es correcta, tiene problemas ya que usar un receptor de transmisión no es una buena idea para este problema. Si su actividad ya ha llamado al método Destroy (), no obtendrá el receptor. La mejor solución es tener un valor booleano en sus preferencias compartidas y verificarlo en el método onCreate () de su actividad. Si no se debe llamar cuando el usuario no está conectado, entonces termine la actividad. Aquí hay un código de muestra 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 engañosa. Así es como lo hice:

    LoginActivity es la actividad raíz de la tarea, configure android: noHistory = “true” en Manifest.xml; Digamos que quiere cerrar sesión desde 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 se me ocurrió en mi aplicación.

    En mi LoginActivity, después de procesar con éxito un inicio de sesión, comienzo 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); } 

    Luego en mi método LoginActivity onActivityForResult:

     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 cierre de sesión 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 desde MainActivity, LoginActivity se oculta inmediatamente. En Honeycomb y más tarde, acabo de terminar la LoginActivity después de procesar un inicio de sesión y se recrea correctamente después de procesar el cierre de sesión.

    Eventime finish() no funciona

    He resuelto ese problema con

    finishAffinity()

    Comience su actividad con StartActivityForResult y, mientras finaliza la sesión, configure su resultado y, según su resultado, termine su 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 siempre 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 Killing navega directamente a una pantalla del medio. Por ejemplo, en un flujo de A-> B-> C, navegue como: Inicio de sesión -> B -> C -> Presione el acceso directo a inicio. El uso de FLAG_ACTIVITY_CLEAR_TOP solo borra la actividad C, ya que Home (A) no está en el historial de la stack. Presionando Atrás en una pantalla nos llevará de nuevo a B.

    Para abordar este problema, podemos mantener una stack de actividades (lista de distribución) y cuando se presiona el inicio, tenemos que eliminar todas las actividades de esta stack.

    Es posible al administrar una bandera en SharedPreferences o en Application Activity.

    Al iniciar la aplicación (en la pantalla de bienvenida) establece el indicador = falso; Al cerrar la sesión, haga clic en el evento solo establezca el indicador verdadero y en OnResume () de cada actividad, verifique si la bandera es verdadera y luego llame a 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 Activity anterior llama este código anterior nuevamente hasta que termines 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); 

    Sugeriría un enfoque diferente a esta pregunta. Tal vez no sea el más eficiente, pero creo que es el más fácil de aplicar y requiere muy poco código. Escribir el siguiente código en su primera actividad (actividad de inicio de sesión, en mi caso) no permitirá al usuario volver a las actividades iniciadas previamente después de cerrar la sesión.

     @Override public void onBackPressed() { // disable going back to the MainActivity moveTaskToBack(true); } 

    Supongo que LoginActivity finaliza justo después de que el usuario inicie sesión, por lo que no puede volver más tarde presionando el botón Atrás. En cambio, el usuario debe presionar un botón de cerrar sesión dentro de la aplicación para cerrar la sesión correctamente. Lo que implementaría este botón de cierre de sesión es una simple intención de la siguiente manera:

     Intent intent = new Intent(this, LoginActivity.class); startActivity(intent); finish(); 

    Todas las sugerencias son bienvenidas

    Una opción es tener el estado de inicio de sesión activado de comprobación de cada actividad, y finalizar () si no está conectado. No me gusta esta opción, ya que el botón Atrás estará disponible para su uso, navegando hacia atrás mientras las actividades se cierran.

    Lo que quiere hacer es llamar a logout () y finish () en sus métodos onStop () o onPause (). Esto obligará a Android a invocar onCreate () cuando la actividad vuelva a activarse, ya que ya no estará en la stack de su actividad. Luego haz lo que dices, en onCreate () revisa el estado de inicio de sesión y reenvía a la pantalla de inicio de sesión si no estás conectado.

    Otra cosa que podría hacer es verificar el estado de inicio de sesión en onResume (), y si no está conectado, finalizar () y ejecutar la actividad de inicio de sesión.