我的应用程序中的所有活动都要求用户登录才能查看 . 用户几乎可以从任何活动中注销 . 这是应用程序的要求 . 在任何时候,如果用户注销,我想将用户发送到登录 Activity
. 此时我希望此活动位于历史堆栈的底部,以便按"back"按钮将用户返回到Android的主屏幕 .
我已经看到这个问题问了几个不同的地方,都回答了类似的答案(我在这里概述),但我想在这里提出收集反馈 .
我已经尝试通过将 Intent
标志设置为 FLAG_ACTIVITY_CLEAR_TOP
来打开Login活动,这似乎与文档中概述的一样,但是没有实现我将Login活动放在历史堆栈底部并且阻止用户导航回以前看到的登录活动 . 我也尝试在清单中使用 android:launchMode="singleTop"
作为登录活动,但这也没有实现我的目标(并且似乎无论如何都没有效果) .
我相信我需要清除历史堆栈,或者完成之前打开的所有活动 .
一种选择是让每个活动的 onCreate
检查登录状态,如果没有登录,则为 finish()
. 我不喜欢这个选项,因为后退按钮仍然可以使用,当活动靠近时自动导航 .
下一个选项是维护 LinkedList
对所有可从任何地方静态访问的打开活动的引用(可能使用弱引用) . 注销时,我将访问此列表并迭代所有先前打开的活动,在每个活动上调用 finish()
. 我很快就会开始实施这种方法 .
不过,我宁愿使用一些 Intent
标志技巧来实现这一目标 . 我不需要使用上面概述的两种方法中的任何一种 .
有没有办法通过使用 Intent
或清单设置来实现这一点,或者是我的第二个选择,保持 LinkedList
已打开的活动是最佳选择?还是有另一种选择,我完全忽略了?
18 回答
我可以建议你另一种方法恕我直言更强大 . 基本上,您需要向需要保持登录状态的所有活动广播注销消息 . 因此,您可以使用
sendBroadcast
并在所有Actvities中安装BroadcastReceiver
. 像这样的东西:接收者(安全活动):
一个新的Android程序员花了一天时间研究这个问题并阅读所有这些StackOverflow线程似乎是一种成熟的仪式 . 我现在是新成立的,我离开这里看看我的谦逊经历,以帮助未来的朝圣者 .
首先,根据我的研究,没有明显或直接的方法可以做到这一点
(as of September 2012).
你认为你可以简单startActivity(new Intent(this, LoginActivity.class), CLEAR_STACK)
但是 no .您可以使用
FLAG_ACTIVITY_CLEAR_TOP
执行startActivity(new Intent(this, LoginActivity.class))
- 这将导致框架向下搜索堆栈,找到您之前的LoginActivity原始实例,重新创建它并清除其余的(向上)堆栈 . 由于Login可能位于堆栈的底部,因此您现在有一个空堆栈,而Back按钮就会退出应用程序 .但是 - 这只有在您之前在堆栈底部保留原始LoginActivity实例时才有效 . 如果像许多程序员一样,一旦用户成功登录就选择了
finish()
,那么它就不再位于堆栈的基础上而且FLAG_ACTIVITY_CLEAR_TOP
语义不适用...你最终会创建一个新的LoginActivity
现有的堆栈 . 这几乎肯定不是你想要的(奇怪的行为,用户可以'back'他们的方式登出到以前的屏幕) .因此,如果您之前有
LoginActivity
,那么您需要寻求一些机制来清除堆栈,然后启动新的LoginActivity
. 似乎@doreamon
在这个帖子中的答案是最好的解决方案(至少对我不起眼的看法):https://stackoverflow.com/a/9580057/614880
我强烈怀疑你是否将LoginActivity保持活着这一棘手的问题导致了很多这种混乱 .
祝好运 .
UPDATE
超级
finishAffinity()
方法将有助于减少代码但实现相同 . 它将完成当前活动以及堆栈中的所有活动,如果您在片段中,则使用getActivity().finishAffinity()
.ORIGINAL ANSWER
假设LoginActivity - > HomeActivity - > ... - > SettingsActivity调用signOut():
HomeActivity:
这对我有用,希望它对你也有帮助 . :)
如果您使用的是API 11或更高版本,可以试试这个:FLAG_ACTIVITY_CLEAR_TASK - 它似乎正在解决您遇到的问题 . 显然,前API 11的人群将不得不使用一些组合,让所有活动检查额外的,如@doreamon建议,或其他一些技巧 .
(另请注意:要使用此功能,您必须传入
FLAG_ACTIVITY_NEW_TASK
)一世这也花了几个小时...并且同意FLAG_ACTIVITY_CLEAR_TOP听起来像你想要的:清除整个堆栈,除了正在启动的活动,所以Back按钮退出应用程序 . 然而正如Mike Repass所提到的,FLAG_ACTIVITY_CLEAR_TOP仅在您没有的活动时起作用,该标志不做任何事情 .
该怎么办?使用FLAG_ACTIVITY_NEW_TASK将正在启动的活动放入堆栈中,这会使该活动成为历史堆栈上新任务的开始 . 然后添加FLAG_ACTIVITY_CLEAR_TOP标志 .
现在,当FLAG_ACTIVITY_CLEAR_TOP在堆栈中查找新活动时,它将在那里并在其他所有清除之前被拉起 .
这是我的退出功能; View参数是函数附加的按钮 .
很多答案 . 可能这个也会有所帮助 -
使用它,它应该对您有所帮助 . 稍微修改了xbakesx的答案 .
接受的解决方案不正确,它有问题,因为使用广播接收器对这个问题不是一个好主意 . 如果你的活动已经调用了onDestroy()方法,你就不会得到接收者 . 最佳解决方案是在共享首选项上使用布尔值,并在您的activty的onCreate()方法中检查它 . 如果在用户未登录时不应该调用它,则完成活动 . 这是示例代码 . 如此简单,适用于各种条件 .
选择的答案很聪明,也很棘手 . 我是这样做的:
LoginActivity是任务的根活动,在Manifest.xml中为它设置 android:noHistory="true" ;假设您要从SettingsActivity注销,您可以执行以下操作:
这是我在我的应用程序中提出的解决方案 .
在我的LoginActivity中,成功处理登录后,我会根据API级别以不同方式启动下一个登录 .
然后在我的LoginActivity的onActivityForResult方法中:
最后,在处理任何其他Activity中的注销后:
在使用Gingerbread时,如果我按下MainActivity中的后退按钮,则会立即隐藏LoginActivity . 在Honeycomb之后,我只是在处理登录后完成LoginActivity,并在处理注销后正确地重新创建 .
有时
finish()
无法正常工作我已经解决了这个问题
finishAffinity()
我建议采用不同的方法解决这个问题 . 也许它不是最有效的,但我认为这是最容易应用的,并且只需要很少的代码 . 在第一个活动中编写下一个代码(在我的情况下,登录活动)将不会让用户在注销后返回先前启动的活动 .
我假设LoginActivity刚刚在用户登录后完成,因此他以后不能通过按后退按钮返回到它 . 相反,用户必须按下应用程序内的注销按钮才能正确注销 . 这个注销按钮将实现的是一个简单的意图如下:
欢迎所有建议 .
使用StartActivityForResult开始您的活动,并在您注销时设置您的结果,并根据您的结果完成您的活动
@doreamon提供的解决方案适用于所有情况,除了一个:
如果登录后,Killing Login屏幕用户直接导航到中间屏幕 . 例如在A-> B-> C的流程中,导航如:登录 - > B - > C - >按快捷键到主页 . 使用FLAG_ACTIVITY_CLEAR_TOP仅清除C活动,因为主页(A)不在堆栈历史记录中 . 按回屏幕将返回B.
为了解决这个问题,我们可以保留一个活动堆栈(Arraylist),当按下home时,我们必须杀死这个堆栈中的所有活动 .
可以通过在SharedPreferences或Application Activity中管理标志来实现 .
在启动应用程序时(在启动画面上)设置flag = false;在Logout Click事件中,只需将标志设置为true,并在每个活动的OnResume()中,检查flag是否为true,然后调用finish() .
它像一个魅力:)
点击Logout,您可以调用它
之前的Activity的onActivityResult()再次调用上面的代码,直到您完成所有活动 .
这对我有用:
你想要做的是在你的onStop()或onPause()方法上调用logout()和finish() . 这将迫使Android在重新启动活动时调用onCreate(),因为它不会再将其放入其活动的堆栈中 . 然后如你所说,在onCreate()中检查登录状态,如果没有登录则转发到登录屏幕 .
您可以做的另一件事是检查onResume()中的登录状态,如果没有登录,则完成()并启动登录活动 .