在我的应用程序的所有活动都需要用户登录后才能查看。 用户可以从几乎任何活动注销。 这是应用程序的要求。 在任何时候,如果用户登录手续,我想给用户发送到登录Activity
。 在这一点上我想这个活动是在历史堆栈的底部,以便按“返回”按钮,使用户返回到Android的主屏幕。
我已经看到了这个问题问了几个不同的地方,它们都具有类似的答案(我在这里概述)回答,但我想在这里提出它来收集反馈。
我试着打开通过设置登录活动Intent
标志来FLAG_ACTIVITY_CLEAR_TOP
这似乎做如文档中概述,但并没有达到我的放置登录活动在历史堆栈的底部,并防止用户的目标导航回到以前见过登录活动。 我使用也尝试过android:launchMode="singleTop"
的清单中的登录活动,但这并不能达到我的目标是(而且似乎有反正没有影响)。
我相信我需要可以清除历史堆栈,或者完成所有previously-开业活动。
一种选择是让每个活动的onCreate
检查登录状态,并finish()
如果没有登录项。 我不喜欢这个选项,返回按钮将仍然可以使用,导航追溯到活动封闭自己。
下一个选项是维持一个LinkedList
引用的所有公开活动是来自世界各地的静态访问(可能使用弱引用)。 在注销我将访问列表和遍历所有先前打开的活动,调用finish()
上的每一个。 我可能会很快开始实施这一方法。
我宁愿用一些Intent
标志弄虚作假做到这一点,但是。 我很高兴以后发现我可以实现我的应用程序的需求,而无需使用任何我先前提到的两种方法。
有没有办法通过使用来完成这个Intent
或清单的设置,或者是我的第二个选项,保持LinkedList
打开活动的最佳选择? 或者是有说我完全可以俯瞰另一种选择?
Answer 1:
我可以建议你恕我直言更强大的另一种方法。 基本上你需要广播登出消息,所有的活动需要留下登录状态。 所以,你可以使用sendBroadcast
和安装BroadcastReceiver
在所有Actvities。 事情是这样的:
/** on your logout method:**/
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("com.package.ACTION_LOGOUT");
sendBroadcast(broadcastIntent);
所述接收器(安全性):
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 **//
}
Answer 2:
It seems a rite of passage that a new Android programmer spends a day researching this issue and reading all of these StackOverflow threads. I am now newly initiated and I leave here trace of my humble experience to help a future pilgrim.
First, there is no obvious or immediate way to do this per my research (as of September 2012).
You'd think you could simple startActivity(new Intent(this, LoginActivity.class), CLEAR_STACK)
but no.
You CAN do startActivity(new Intent(this, LoginActivity.class))
with FLAG_ACTIVITY_CLEAR_TOP
- and this will cause the framework to search down the stack, find your earlier original instance of LoginActivity, recreate it and clear the rest of the (upwards) stack. And since Login is presumably at the bottom of the stack, you now have an empty stack and the Back button just exits the application.
BUT - this only works if you previously left that original instance of LoginActivity alive at the base of your stack. If, like many programmers, you chose to finish()
that LoginActivity
once the user has successfully logged in, then it's no longer on the base of the stack and the FLAG_ACTIVITY_CLEAR_TOP
semantics do not apply ... you end up creating a new LoginActivity
on top of the existing stack. Which is almost certainly NOT what you want (weird behavior where the user can 'back' their way out of login into a previous screen).
So if you have previously finish()
'd the LoginActivity
, you need to pursue some mechanism for clearing your stack and then starting a new LoginActivity
. It seems like the answer by @doreamon
in this thread is the best solution (at least to my humble eye):
https://stackoverflow.com/a/9580057/614880
I strongly suspect that the tricky implications of whether you leave LoginActivity alive are causing a lot of this confusion.
Good Luck.
Answer 3:
UPDATE
超级finishAffinity()
方法将有助于减少代码,但达到相同的。 这将完成当前活动以及堆栈中的所有活动,使用getActivity().finishAffinity()
如果你在一个片段。
finishAffinity();
startActivity(new Intent(mActivity, LoginActivity.class));
原来的答案
假设LoginActivity - > HomeActivity - > - > SettingsActivity调用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();
}
这对我的作品,希望它能对你也有帮助。 :)
Answer 4:
如果使用的是API 11或更高版本,你可以试试这个: FLAG_ACTIVITY_CLEAR_TASK
--IT似乎正好解决您遇到的问题。 显然,-API前11的人群将不得不使用具有所有活动检查的额外,作为@doreamon建议,或其他一些挂羊头卖狗肉的某种组合。
(另请注意:使用这个你必须通过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();
Answer 5:
我花了几个小时,在这个太...并同意FLAG_ACTIVITY_CLEAR_TOP听起来像你想要什么:清除整个堆栈,除了活动正在展开,所以后退按钮退出应用程序。 然而,正如麦克REPASS提到,FLAG_ACTIVITY_CLEAR_TOP只有当你推出的活动已经在堆栈工程; 当活动的不存在,该标志不会做任何事情。
该怎么办? 把活动是在栈推出FLAG_ACTIVITY_NEW_TASK ,这使得该活动的历史堆栈上一个新任务的开始。 然后添加FLAG_ACTIVITY_CLEAR_TOP标志。
现在,当FLAG_ACTIVITY_CLEAR_TOP去寻找堆栈中的新的活动,它会在那里和其他一切清零之前被拉高。
这是我的注销功能; 查看参数是对功能的附加其中的按钮。
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();
}
Answer 6:
很多答案。 可能是这其中也将帮助 -
Intent intent = new Intent(activity, SignInActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(intent);
this.finish();
Answer 7:
使用这个应该对你有所帮助。 稍微修改xbakesx答案。
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);
Answer 8:
接受的解决方案是不正确的,它有问题,使用的广播接收器是不是这个问题的好方法。 如果你的活动已叫的onDestroy()方法,你不会得到接收机。 最好的解决办法是有您共享偏好一个布尔值,并在activty的onCreate()方法检查它。 如果在不登录的用户不应该被调用,然后完成活动。 下面是示例代码为。 如此简单,适用于所有的情况。
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;
}
Answer 9:
所选择的答案是聪明和狡猾。 以下是我做的:
LoginActivity是任务的根系活力,集机器人:在的Manifest.xml noHistory =“true”以它; 假设你想从SettingsActivity登出,你可以如下做到这一点:
Intent i = new Intent(SettingsActivity.this, LoginActivity.class);
i.addFlags(IntentCompat.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
Answer 10:
下面是我在我的应用程序提出了解决方案。
在我LoginActivity,成功处理后登录后,我开始下一个不同,这取决于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);
}
然后在我的LoginActivity的onActivityForResult方法:
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);
当姜饼,使得它如此,如果我按从MainActivity后退按钮时,LoginActivity立即隐藏。 在蜂窝后来,我只是完成了LoginActivity处理登录后,它处理注销后正确地重新创建。
Answer 11:
有时finish()
不工作
我已经解决了这个问题
finishAffinity()
Answer 12:
我建议不同的方法来这个问题。 也许这不是最有效的,但我认为这是最简单的应用只需要很少的代码。 在你的第一个活动(登录活动,在我的情况),写入下一个代码不会让用户返回到先前下水的活动注销后。
@Override
public void onBackPressed() {
// disable going back to the MainActivity
moveTaskToBack(true);
}
我假设LoginActivity只是在用户登录后完成,所以他不能回去以后它按后退按钮。 相反,用户必须以正确注销按应用程序内注销按钮。 这是什么注销按钮将实现一个简单的目的如下:
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
finish();
所有建议都欢迎。
Answer 13:
你开始用活动和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);
}
Answer 14:
提供的解决方案@doreamon工作正常,除此之外的所有情况:
如果登录后,杀死登录界面用户直接导航到屏幕中间。 如在A-> B->℃的流动,像导航:登录 - “乙 - ”ç - >按快捷方式回家。 使用FLAG_ACTIVITY_CLEAR_TOP只清除C活性,作为家庭(A)是不是在堆栈历史记录。 按返回上一个屏幕上会引领我们回到B.
为了解决这个问题,我们可以保持的活动堆栈(数组列表),并按下家的时候,我们要杀死这个堆中的所有活动。
Answer 15:
它通过在SharedPreferences或应用程序管理活动中的一个标志是可能的。
上的应用程序的(上启动画面)开始设置该标志=假; 在注销点击事件只是设置标志真实和的onResume()的每一次活动中,检查是否标志为真,则调用finish()。
它的工作原理就像一个魅力:)
Answer 16:
在退出的点击,你可以调用这个
private void GoToPreviousActivity() {
setResult(REQUEST_CODE_LOGOUT);
this.finish();
}
onActivityResult(),直到你完成了所有的活动,以前的活动调用这个上面再代码。
Answer 17:
这为我工作:
// 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);
Answer 18:
一种选择是让每个活动的onCreate检查登录状态,并完成()如果没有登录项。 我不喜欢这个选项,返回按钮将仍然可以使用,导航追溯到活动封闭自己。
你想要做的就是调用注销()和完成()在你的onStop()或在onPause()方法。 这将迫使Android的调用的onCreate()在活动被带回上,因为它不会在其活动的堆栈中的任何更长的时间。 然后做像你说的,在的onCreate()检查已登录状态,并转发到登录屏幕,如果没有登录。
你可以做的另一件事是检查,如果没有登录,完成()登录状态中的onResume(),并和发射登录活动。
文章来源: On logout, clear Activity history stack, preventing “back” button from opening logged-in-only Activities