365

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

情况

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

在屏幕 C 中,用户可能会采取使屏幕 B 无效的操作,因此应用程序希望将他们带到屏幕 A,而不管它是否已经在堆栈中。然后,屏幕 A 应该是我的应用程序堆栈中的唯一项目。

笔记

还有许多其他类似的问题,但我还没有找到任何可以回答这个确切问题的东西。我尝试调用getParent().finish()- 这总是导致空指针异常。FLAG_ACTIVITY_CLEAR_TOP仅当活动已经在堆栈上时才有效。

4

13 回答 13

714

在 API 级别 11 中,为此添加了一个新的 Intent 标志: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”解决方案确实是纯粹的骇客。你不应该那样做。:)

编辑: 根据@ Ben Pearson的评论,对于 API <=10,现在可以使用IntentCompat类。可以使用IntentCompat.FLAG_ACTIVITY_CLEAR_TASK标志来清除任务。所以你也可以支持 pre API level 11。

于 2011-03-17T20:10:09.090 回答
54

案例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 清除堆栈并使其成为顶部。所以当我们按下返回按钮时,整个应用程序将被终止。

于 2013-05-03T12:45:55.383 回答
51

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

方法适用于 >= API 16。

Intent mIntent = new Intent(mContext,MainActivity.class);
finishAffinity();
startActivity(mIntent);
  • 和启动新的Activity一样,清空所有栈。
  • 或重新启动到 MainActivity/FirstActivity。
于 2016-09-14T07:19:11.090 回答
26

我也花了几个小时...并同意 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();
}
于 2013-10-18T15:29:06.207 回答
13

在您开始一项新活动后,立即使用startActivity,确保您调用finish(),以便当前活动不会堆叠在新活动后面。

于 2012-04-04T16:44:45.870 回答
13

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

我可以想到一种方法来做到这一点,但它是一个相当黑客。

  • singleTask通过将其添加到AndroidManifest 示例中来制作您的活动:

    <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"/>
    
  • 扩展Application它将保存去哪里的逻辑。

例子:

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()并从堆栈中处理后退按钮。

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

于 2010-08-13T01:59:03.610 回答
8

高级可重用 Kotlin:

您可以使用 setter 方法直接设置标志。在 Kotlinor中是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.clearStack()

如果您需要在其他情况下添加附加标志的选项,请在扩展函数中添加一个可选参数。

fun Intent.clearStack(additionalFlags: Int = 0) {
    flags = additionalFlags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
于 2020-01-07T20:07:03.483 回答
5

试试下面的代码,

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);
于 2018-11-14T08:39:59.777 回答
5

尝试这个:

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();
于 2017-06-13T04:29:01.257 回答
3

对我来说,上述方法不起作用。

只需执行此操作即可清除所有以前的活动

finishAffinity() // if you are in fragment use activity.finishAffinity()
Intent intent = new Intent(this, DestActivity.class); // with all flags you want
startActivity(intent)
于 2019-05-24T10:38:28.560 回答
2
Intent i = new Intent(MainPoliticalLogin.this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
于 2017-12-13T11:56:04.517 回答
-1

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

于 2016-10-06T09:08:54.207 回答
-2

我发现太简单的黑客只是这样做添加新元素 AndroidManifest: -

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

android:noHistory将从堆栈中清除您不需要的活动。

于 2016-07-19T08:43:59.067 回答