是否可以在堆栈上启动一个活动,清除它之前的整个历史记录?
情况
我有一个活动堆栈,可以是 A->B->C 或 B->C(屏幕 A 选择用户令牌,但许多用户只有一个令牌)。
在屏幕 C 中,用户可能会采取使屏幕 B 无效的操作,因此应用程序希望将他们带到屏幕 A,而不管它是否已经在堆栈中。然后,屏幕 A 应该是我的应用程序堆栈中的唯一项目。
笔记
还有许多其他类似的问题,但我还没有找到任何可以回答这个确切问题的东西。我尝试调用 getParent().finish()
- 这总是会导致空指针异常。 FLAG_ACTIVITY_CLEAR_TOP
仅在 Activity 已在堆栈中时才有效。
在 API 级别 11 中,为此添加了一个新的意图标志:Intent.FLAG_ACTIVITY_CLEAR_TASK
只是为了澄清,使用这个:
爪哇
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
科特林
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
不幸的是,对于 API lvl <= 10,我还没有找到一个干净的解决方案。 "DontHackAndroidLikeThis" solution 确实是纯粹的骇客。你不应该那样做。 :)
编辑:根据@Ben Pearson 的评论,对于 API <=10,现在可以使用 IntentCompat 类。可以使用 IntentCompat.FLAG_ACTIVITY_CLEAR_TASK
标志来清除任务。所以你也可以支持 pre API level 11。
案例1:只有两个活动A和B:
这里 Activity 流程是 A->B 。在从 B 单击后退按钮时,我们需要关闭应用程序,然后在从 A 启动 Activity B 时只需调用 finish() 这将阻止 android 将 Activity A 存储到 Backstack 中。例如,活动 A 是加载/启动应用程序屏幕。
Intent newIntent = new Intent(A.this, B.class);
startActivity(newIntent);
finish();
案例2:两个以上的活动:
如果有像 A->B->C->D->B 这样的流程,并且在来自 Activity D 时单击 Activity B 中的后退按钮。在这种情况下,我们应该使用。
Intent newIntent = new Intent(D.this,B.class);
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(newIntent);
这里 Activity B 将从后台堆栈而不是新实例启动,因为 Intent.FLAG_ACTIVITY_CLEAR_TOP 和 Intent.FLAG_ACTIVITY_NEW_TASK 清除堆栈并使其成为顶部。所以当我们按下返回按钮时,整个应用程序将被终止。
Android 的较新版本 >= API 16 使用 finishAffinity()
方法适用于 >= API 16。
Intent mIntent = new Intent(mContext,MainActivity.class);
finishAffinity();
startActivity(mIntent);
和启动新的Activity一样,清空所有栈。
或重新启动到 MainActivity/FirstActivity。
我也花了几个小时...并同意 FLAG_ACTIVITY_CLEAR_TOP 听起来像你想要的:清除整个堆栈,除了正在启动的活动,所以后退按钮退出应用程序。然而,正如 Mike Repass 所提到的, FLAG_ACTIVITY_CLEAR_TOP 仅在您启动的活动已经在堆栈中时才有效;当活动不存在时,标志不会做任何事情。
该怎么办?将正在启动的活动放入带有 FLAG_ACTIVITY_NEW_TASK 的堆栈中,这使得该活动成为历史堆栈上新任务的开始。然后添加 FLAG_ACTIVITY_CLEAR_TOP 标志。
现在,当 FLAG_ACTIVITY_CLEAR_TOP 在堆栈中查找新活动时,它会在那里并在其他所有内容被清除之前被拉起。
这是我的注销功能; View 参数是函数附加到的按钮。
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();
}
使用 startActivity
启动新活动后,请立即确保调用 finish()
,以免当前活动堆积在新活动后面。
你不应该改变堆栈。 Android 后退按钮应该像在网络浏览器中一样工作。
我可以想到一种方法来做到这一点,但它是一个相当黑客。
将您的活动添加到 AndroidManifest 示例中,使其成为 singleTask:
扩展应用程序,它将保存去哪里的逻辑。
例子:
public class DontHackAndroidLikeThis extends Application {
private Stack<Activity> classes = new Stack<Activity>();
public Activity getBackActivity() {
return classes.pop();
}
public void addBackActivity(Activity activity) {
classes.push(activity);
}
}
从 A 到 B:
DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
app.addBackActivity(A.class);
startActivity(this, B.class);
从 B 到 C:
DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
app.addBackActivity(B.class);
startActivity(this, C.class);
在 C 中:
If ( shouldNotGoBackToB() ) {
DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
app.pop();
}
并将返回按钮从堆栈中处理为 pop()
。
再一次,你不应该这样做:)
Application
获取了它们的实例,操作系统将无法从被破坏的活动中释放剩余的 RAM。
高级可重用 Kotlin:
您可以使用 setter 方法直接设置标志。在 Kotlin 中,or
是 Java 按位的 replacement 或 |
。
intent.flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK
如果您打算定期使用它,请创建一个 Intent 扩展功能
fun Intent.clearStack() {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
然后,您可以在启动意图之前直接调用此函数
intent.clearStack()
如果您需要在其他情况下添加附加标志的选项,请在扩展函数中添加一个可选参数。
fun Intent.clearStack(additionalFlags: Int = 0) {
flags = additionalFlags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
试试下面的代码,
Intent intent = new Intent(ManageProfileActivity.this, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
Intent.FLAG_ACTIVITY_CLEAR_TASK|
Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
尝试这个:
Intent logout_intent = new Intent(DashboardActivity.this, LoginActivity.class);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(logout_intent);
finish();
对我来说,上述方法都不起作用。
只需执行此操作即可清除所有以前的活动:
finishAffinity() // if you are in fragment use activity.finishAffinity()
Intent intent = new Intent(this, DestActivity.class); // with all flags you want
startActivity(intent)
Intent i = new Intent(MainPoliticalLogin.this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
有时您的 android 模拟器可能无法连接 eclipse DDMS 工具并要求手动启动 adb。在这种情况下,您可以使用命令提示符启动或停止 adb。
我发现太简单了,只需在 AndroidManifest
中添加新元素即可:-
<activity android:name=".activityName"
android:label="@string/app_name"
android:noHistory="true"/>
android:noHistory
将从 Stack 中清除您不需要的活动。