Android 注销时,清除活动历史堆栈,防止;“后退”;打开“仅登录”活动的按钮

Android 注销时,清除活动历史堆栈,防止;“后退”;打开“仅登录”活动的按钮,android,android-lifecycle,activity-lifecycle,Android,Android Lifecycle,Activity Lifecycle,我的应用程序中的所有活动都需要用户登录才能查看。用户几乎可以从任何活动中注销。这是应用程序的一个要求。在任何时候,如果用户注销,我都希望将用户发送到登录活动。此时,我希望此活动位于历史堆栈的底部,以便按下“后退”按钮将用户返回到Android的主屏幕 我看到这个问题问了几个不同的地方,所有的答案都是相似的(我在这里概述),但我想在这里提出它来收集反馈 我尝试通过将登录活动的Intent标志设置为FLAG\u activity\u CLEAR\u TOP来打开登录活动,这似乎与文档中概述的一样,但

我的应用程序中的所有活动都需要用户登录才能查看。用户几乎可以从任何活动中注销。这是应用程序的一个要求。在任何时候,如果用户注销,我都希望将用户发送到登录
活动
。此时,我希望此活动位于历史堆栈的底部,以便按下“后退”按钮将用户返回到Android的主屏幕

我看到这个问题问了几个不同的地方,所有的答案都是相似的(我在这里概述),但我想在这里提出它来收集反馈

我尝试通过将登录活动的
Intent
标志设置为
FLAG\u activity\u CLEAR\u TOP
来打开登录活动,这似乎与文档中概述的一样,但没有实现将登录活动放在历史堆栈底部的目标,以及防止用户导航回以前看到的登录活动。我还尝试在清单中为登录活动使用
android:launchMode=“singleTop”
,但这也没有达到我的目标(而且似乎没有任何效果)

我相信我需要清除历史堆栈,或者完成所有以前打开的活动

一个选项是让每个活动的
onCreate
检查登录状态,如果未登录,则检查
finish()。我不喜欢这个选项,因为“后退”按钮仍然可以使用,在活动自行关闭时导航回去

下一个选项是维护对所有打开活动的引用的
LinkedList
,这些活动可以从任何地方静态访问(可能使用弱引用)。注销时,我将访问此列表并迭代所有以前打开的活动,对每个活动调用
finish()
。我可能很快就会开始实现这个方法

然而,我宁愿使用一些
意图
标记技巧来实现这一点。我会非常高兴地发现,我可以满足我的应用程序的要求,而不必使用上述两种方法中的任何一种

有没有办法通过使用
Intent
或清单设置来实现这一点,或者我的第二个选项,维护已打开活动的
LinkedList
是最佳选项?还是我完全忽略了另一个选择

一个选项是让每个活动的onCreate检查登录状态,如果未登录,则返回finish()。我不喜欢这个选项,因为“后退”按钮仍然可以使用,在活动自行关闭时导航回去

您要做的是在onStop()或onPause()方法上调用logout()和finish()。这将迫使Android在活动重新启动时调用onCreate(),因为它将不再在其活动堆栈中。然后按照您所说的做,在onCreate()中检查登录状态,如果未登录,则转发到登录屏幕


您可以做的另一件事是在onResume()中检查登录状态,如果未登录,请完成()并启动登录活动。

我可以建议您另一种更可靠的方法。 基本上,您需要向所有需要保持登录状态的活动广播注销消息。因此,您可以在所有活动中使用
sendBroadcast
并安装
BroadcastReceiver
。 大概是这样的:

/** on your logout method:**/
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("com.package.ACTION_LOGOUT");
sendBroadcast(broadcastIntent);
接收方(担保活动):


使用StartActivityForResult开始活动,注销时设置结果,并根据结果完成活动

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

}

单击注销后,您可以将其称为

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

上一个活动的onActivityResult()再次调用上述代码,直到完成所有活动。

更新

super
finishafinity()
方法将有助于减少代码,但实现相同的效果。它将完成当前活动以及堆栈中的所有活动,如果在片段中,请使用
getActivity().finishafinity()

finishAffinity(); 
startActivity(new Intent(mActivity, LoginActivity.class));
原始答案

假设LoginActivity-->HomeActivity-->…-->SettingsActivity调用注销():

家庭活动:

@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();
}

这对我很有用,希望对你也有帮助。:)

一位新的安卓程序员花一天时间研究这个问题,阅读所有这些StackOverflow线程,这似乎是一种仪式。我现在是新入行的,我在这里留下我卑微的经历的痕迹,以帮助未来的朝圣者

首先,根据我的研究
(截至2012年9月),没有明显或直接的方法可以做到这一点。
你可能认为你可以简单地
开始操作(新意图(这个,LoginActivity.class),清除\u堆栈)
但是没有

您可以使用
FLAG\u ACTIVITY\u CLEAR\u TOP
执行
startActivity(new Intent(this,LoginActivity.class))
,这将导致框架向下搜索堆栈,找到LoginActivity的早期原始实例,重新创建它并清除(向上)堆栈的其余部分。由于Login可能位于堆栈的底部,所以现在有一个空堆栈,而Back按钮只是退出应用程序

但是-只有当您之前将LoginActivity的原始实例保留在堆栈的底部时,这才有效。如果像许多程序员一样,一旦用户成功登录,您选择
finish()
LoginActivity
,那么它就不再位于堆栈的基础上,并且
标志\u活动\u清除\u顶部
语义不适用。。。您最终将在现有堆栈的顶部创建一个新的
LoginActivity
。这几乎肯定不是你想要的(奇怪的行为,用户可以“返回”登录到上一个屏幕)

因此,如果您以前有
finish()
'd
LoginActivity
,则需要采用某种机制来清除堆栈,然后
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();
}
@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();
}
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();
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();
}
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);
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB &&
        requestCode == REQUEST_LOGIN_GINGERBREAD &&
        resultCode == Activity.RESULT_CANCELED) {
    moveTaskToBack(true);
}
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);
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);
    Intent i = new Intent(SettingsActivity.this, LoginActivity.class);
    i.addFlags(IntentCompat.FLAG_ACTIVITY_CLEAR_TASK
            | Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(i);
     // 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);
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;
}
Intent intent = new Intent(activity, SignInActivity.class)
                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(intent);
this.finish();
Intent(this, SignInActivity::class.java).apply {
    addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}.also { startActivity(it) }
finish()
@Override
public void onBackPressed() {
    // disable going back to the MainActivity
    moveTaskToBack(true);
}
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
finish();