Al cerrar sesión, borre la pila del historial de actividades, evitando que el botón "atrás" abra actividades en las que solo se ha iniciado sesión.

Resuelto skyler asked hace 54 años • 18 respuestas

Todas las actividades en mi aplicación requieren que un usuario inicie sesión para poder verlas. Los usuarios pueden cerrar sesión en casi cualquier actividad. Este es un requisito de la aplicación. En cualquier momento, si el usuario cierra sesión, quiero enviarlo al inicio de sesión Activity. En este punto, quiero que esta actividad esté en la parte inferior de la pila del historial para que al presionar el botón "atrás" el usuario regrese a la pantalla de inicio de Android.

He visto esta pregunta formulada en diferentes lugares, todas respondidas con respuestas similares (que describo aquí), pero quiero plantearla aquí para recopilar comentarios.

Intenté abrir la actividad de inicio de sesión configurando sus Intentindicadores, FLAG_ACTIVITY_CLEAR_TOPlo que parece funcionar como se describe en la documentación, pero no logro mi objetivo de colocar la actividad de inicio de sesión en la parte inferior de la pila del historial y evitar que el usuario regrese. a actividades registradas previamente vistas. También intenté usarlo android:launchMode="singleTop"para la actividad de inicio de sesión en el manifiesto, pero esto tampoco logra mi objetivo (y parece no tener ningún efecto de todos modos).

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

Una opción es que cada actividad onCreateverifique el estado de inicio de sesión y, finish()si no, de inicio de sesión. No me gusta esta opción, ya que el botón Atrás seguirá estando disponible para su uso, navegando hacia atrás a medida que las actividades se cierran solas.

La siguiente opción es mantener una LinkedListserie de referencias a todas las actividades abiertas a las que se pueda acceder estáticamente desde cualquier lugar (quizás usando referencias débiles). Al cerrar sesión, accederé a esta lista y recorreré todas las actividades abiertas anteriormente, invocando finish()cada una de ellas. Probablemente comenzaré a implementar este método pronto.

Sin embargo , prefiero usar algunos Intenttrucos de banderas para lograr esto. Estaría más que feliz de saber que puedo cumplir con los requisitos de mi aplicación sin tener que usar ninguno de los dos métodos que describí anteriormente.

¿Hay alguna manera de lograr esto mediante el uso Intentde la configuración de manifiesto, o mi segunda opción, mantener una LinkedListde actividades abiertas, es la mejor opción? ¿O hay otra opción que estoy pasando por alto por completo?

skyler avatar Jan 01 '70 08:01 skyler
Aceptado

Puedo sugerirle otro enfoque, en mi humilde opinión, más sólido. Básicamente, necesita transmitir un mensaje de cierre de sesión a todas sus actividades que deben permanecer en estado de inicio de sesión. Para que pueda utilizar sendBroadcaste instalar BroadcastReceiveren todas sus actividades. 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 **//
}
Francesco Laurita avatar Jun 09 '2010 18:06 Francesco Laurita

Parece un rito de iniciación que un nuevo programador de Android pase un día investigando este tema y leyendo todos estos hilos de StackOverflow. Ahora soy recién iniciado y dejo aquí huella de mi humilde experiencia para ayudar a un futuro peregrino.

En primer lugar, según mi investigación, no existe una forma obvia o inmediata de hacer esto. (as of September 2012).Uno pensaría que podría ser simple, startActivity(new Intent(this, LoginActivity.class), CLEAR_STACK)pero no .

PUEDE hacerlo startActivity(new Intent(this, LoginActivity.class)), FLAG_ACTIVITY_CLEAR_TOPy esto hará que el marco busque en la pila, encuentre su instancia original anterior de LoginActivity, la vuelva a crear y borre el resto de la pila (hacia arriba). Y dado que el inicio de sesión probablemente esté en la parte inferior de la pila, ahora tiene una pila vacía y el botón Atrás simplemente sale de la aplicación.

PERO: esto solo funciona si previamente dejó viva esa instancia original de LoginActivity en la base de su pila. Si, como muchos programadores, elige finish()eso LoginActivityuna vez que el usuario haya iniciado sesión exitosamente, entonces ya no estará en la base de la pila y la FLAG_ACTIVITY_CLEAR_TOPsemántica no se aplica... terminará creando una nueva LoginActivityencima de la pila existente. Lo cual es casi seguro que NO es lo que desea (comportamiento extraño en el que el usuario puede "retroceder" para salir del inicio de sesión en una pantalla anterior).

Entonces, si ya finish()lo ha hecho anteriormente LoginActivity, debe buscar algún mecanismo para limpiar su pila y luego comenzar una nueva LoginActivity. Parece que la respuesta @doreamonen este hilo es la mejor solución (al menos para mi humilde opinión):

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

Sospecho firmemente que las complicadas implicaciones de dejar con vida LoginActivity están causando gran parte de esta confusión.

Buena suerte.

Mike Repass avatar Sep 17 '2012 23:09 Mike Repass

ACTUALIZAR

el súper finishAffinity()método ayudará a reducir el código pero logrará lo mismo. Finalizará la actividad actual así como todas las actividades en la pila, úsela getActivity().finishAffinity()si está 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();
}

InicioActividad:

@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 ti también. :)

thanhbinh84 avatar Mar 06 '2012 08:03 thanhbinh84