清除整个历史堆栈,并在Android上启动一个新活动

是否有可能在堆栈上启动一个活动,清除它之前的整个历史?

这种情况

我有一个活动堆栈,要么是A->B->C,要么是B->C(屏幕A选择用户令牌,但许多用户只有一个令牌)。

在屏幕C中,用户五月执行了一个使屏幕B无效的操作,因此应用程序希望将他们带到屏幕A,而不管它是否已经在堆栈中。屏幕A应该是我的应用程序堆栈上的唯一项。

笔记

还有很多类似的问题,但我还没有找到任何答案。我尝试调用getParent().finish() -这总是导致空指针异常。FLAG_ACTIVITY_CLEAR_TOP仅在活动已经在堆栈上时才有效。

245062 次浏览

你不应该改变堆栈。Android的后退按钮应该像浏览器一样工作。

我能想出一个办法来做这件事,但这太麻烦了。

    将你的Activities添加到AndroidManifest中,使其成为singleTask 例子:< / p >
    <activity android:name=".activities.A"
    android:label="@string/A_title"
    android:launchMode="singleTask"/>
    
    
    <activity android:name=".activities.B"
    android:label="@string/B_title"
    android:launchMode="singleTask"/>
    
  • Extend Application which will hold the logic of where to go.

Example:

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()的返回按钮。

再说一次,你不应该这样做:)

在API级别11中,添加了一个新的意图标志:意图。FLAG_ACTIVITY_CLEAR_TASK

澄清一下,用这个:

Java

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"解决方案确实是纯粹的hack。你不应该那样做。:) < / p >

<强>编辑: 根据@本·皮尔森的注释,对于API <=10,现在可以使用IntentCompat类。可以使用IntentCompat.FLAG_ACTIVITY_CLEAR_TASK标志来清除任务。所以你也可以支持pre API级别11

在你使用startActivity启动一个新活动之后,确保你调用了finish(),这样当前活动就不会堆叠在新活动的后面。

案例1:只有两个活动A和B:

这里的活动流程是A->B .从B点击后退按钮,我们需要关闭应用程序,然后从A启动活动B,只需调用finish()这将防止android从存储活动A到Backstack。例如,活动A是应用程序的载入/启动屏幕。

Intent newIntent = new Intent(A.this, B.class);
startActivity(newIntent);
finish();

案例2:两个以上的活动:

如果有像a ->B->C->D->B这样的流程,并且在从活动D进入活动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);

由于Intent的原因,Activity B将从backstack而不是一个新实例启动。FLAG_ACTIVITY_CLEAR_TOP和Intent。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参数是函数所附加的按钮。

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

我发现太简单的hack只是这样做,在AndroidManifest中添加新元素:-

<activity android:name=".activityName"
android:label="@string/app_name"
android:noHistory="true"/>

android:noHistory将从Stack中清除你不需要的活动。

对于Android的新版本>= API 16使用finishAffinity()

方法适用于>= API 16。

Intent mIntent = new Intent(mContext,MainActivity.class);
finishAffinity();
startActivity(mIntent);
  • 它是相同的启动新的活动,并清除所有堆栈。
  • 或者重启到MainActivity/FirstActivity。

有时您的android模拟器可能无法连接eclipse DDMS工具,并要求adb手动启动。在这种情况下,您可以使用命令提示符启动或停止adb。

试试这个:

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();
Intent i = new Intent(MainPoliticalLogin.this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);

试试下面的代码,

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

为我没有一个的上述方法不工作。

只需对清除所有先前的活动执行此操作:

finishAffinity() // if you are in fragment use activity.finishAffinity()
Intent intent = new Intent(this, DestActivity.class); // with all flags you want
startActivity(intent)

高级可重用Kotlin:

您可以直接使用setter方法设置标志。在Kotlin中,or是Java位的更换|

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之前直接调用这个函数

intent.clearStack()

如果您需要在其他情况下添加额外标志的选项,请向扩展函数添加可选参数。

fun Intent.clearStack(additionalFlags: Int = 0) {
flags = additionalFlags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}

在爪哇:-

 startActivity(new Intent(getApplicationContext(),ChooseServiceActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));