从历史记录堆栈中删除活动


382

我的应用程序在用户首次运行该应用程序时显示一个注册活动,如下所示:

  1. ActivitySplashScreen(欢迎使用游戏,注册一个帐户?)
  2. ActivitySplashScreenSignUp(很好,请填写此信息)
  3. ActivityGameMain(主游戏屏幕)

因此,当用户单击每个屏幕上的按钮时,活动将以完全相同的顺序彼此启动。

当用户从活动#2转到#3时,是否有可能彻底清除历史记录堆栈中的#1和#2?我希望这样,如果用户位于#3,然后单击“后退”按钮,则他们只是转到主屏幕,而不是返回初始屏幕。

我想我可以通过任务来完成此任务(例如,在#3上开始新任务),但想看看是否有更简单的方法,

谢谢


进入主屏幕后,当用户恢复您的应用时,是否将其带到ActivitySplashScreen或ActivityGameMain?
泰米尔语

Answers:


632

您可以通过设置实现这一android:noHistory 属性,以"true"在相关<activity>的条目AndroidManifest.xml文件。例如:

<activity
    android:name=".AnyActivity"
    android:noHistory="true" />

12
这是最好的方法。
shkschneider 2012年

22
等效地,您可以使用FLAG_ACTIVITY_NO_HISTORY
Timmmm 2012年

34
如何通过代码实现呢?因为我不想一直这样做。我只想在某些情况下将特定活动从历史记录中删除。
Namratha

8
请注意,使用noHistory属性将使该活动完成,例如,使用G +登录可能会导致意外的行为。请参阅:stackoverflow.com/questions/20383878/…花了我一段时间才能找到此错误,因为我的应用程序一直崩溃而无任何踪迹。
阿卡普尔科2014年

13
复制所需的标志很困难,因为它是一个链接,因此这里很容易复制。android:noHistory="true"
MirroredFate

137

您可以在启动下一个活动时使用转发从活动堆栈中删除上一个活动。 APIDemos中有一个示例,但是基本上您要做的就是在调用finish()后立即调用startActivity()


1
丹尼尔,您好,我通读了示例,但这只会按1个活动清除历史记录堆栈,不是吗?如果我的堆栈看起来像A,B,并且我要启动C,我希望C成为新的根并完全清除A和B。在sdk示例中,从B调用finish()会使我留下A的堆栈,C,不是吗?谢谢。
标记

1
您可以在启动B时清除A,并在启动C时清除B;但是,我想如果您想要的话,您将无法从B退回到A。如果这是一个问题,我将不得不对此进行更多考虑。
丹·卢

3
标记要实现所需的功能,必须使用标志:FLAG_ACTIVITY_CLEAR_TOP。希望对您有所帮助。
Francisco Junior

3
FLAG_ACTIVITY_CLEAR_TOP将无法工作,因为C尚未在后堆栈中。
Timmmm 2012年

1
@DanielLew APIDemos中有很多示例。您会得到建议的示例名称吗?
Stephane

52

46
请注意,这不会为您要启动的活动设置任何历史记录。为了没有要启动的活动的历史记录,我只android:noHistory="true"在清单中进行设置。
georgiecasey 2012年

1
这个工作很好。使用intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)设置此标志。
vovahost

1
@georgiecasey有时在您想要保留其历史记录,有时又不希望其保留历史记录时很有用。
Vihaan Verma

24

这可能不是理想的方法。如果有人有更好的方法,我将期待实现它。这是使用11版之前的SDK完成此特定任务的方式。

在每个课余时间都想离开的班级中,您需要这样做:

    ... interesting code stuff ...
    Intent i = new Intent(MyActivityThatNeedsToGo.this, NextActivity.class);
    startActivityForResult(i, 0);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == R.string.unwind_stack_result_id) {
        this.setResult(R.string.unwind_stack_result_id);
        this.finish();
    }
}

那么需要从堆栈中弹出弹出链的对象就需要在您要启动它时调用它:

NextActivity.this.setResult(R.string.unwind_stack_result_id);
NextActivity.this.finish();

那么活动就不在堆栈中!
记住人们,您可以开始一个活动,然后在其后开始清理,执行不遵循单个(ui)线程。


万一以后有人遇到这个问题,我想知道这可能很重要,如果您旋转了屏幕,当您从堆栈中弹出最后一个活动时,android将为您重新启动应用程序。请注意这一点!
特拉维斯

如果您只想根据用户在下一个活动中的操作+1有条件地从堆栈中删除活动,则这是一个很好的答案
The MothaShip 2013年

23

在API 11之前运行的一种方法是先启动ActivityGameMain,然后在该onCreateActivity的其中启动您的ActivitySplashScreen活动。ActivityGameMain当您为启动启动太早调用startActivity时,将不会出现。

然后,您可以ActivityGameMain通过在Intent上设置以下标志清除堆栈:

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);

您还必须将其添加到ActivitySplashScreen:

@Override
public void onBackPressed() {
    moveTaskToBack(true);
}

这样一来,按回该活动就不会回到您的ActivityGameMain

我假设您不希望启动画面回到任何一个,要实现此目的,建议noHistory您在中将其设置为AndroidManifest.xml。然后将goBackPressed代码放入您的ActivitySplashScreenSignUp类中。

但是,我发现了几种方法可以解决此问题。在出现的通知中启动另一个应用程序,ActivitySplashScreenSignUp并且历史记录未重置。

解决此问题的唯一真正方法是在API 11中:

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);

20

我用这种方式。

Intent i = new Intent(MyOldActivity.this, MyNewActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(i);

谢谢。我发现菜单中有一个“主页”按钮时,这很有用,并且我不希望用户单击主页后出现堆叠的活动。
ghitesh

8

我知道我迟到了(问了问题已经两年了),但是我是通过拦截后退按钮来实现的。而不是检查特定活动,我只是查看计数,如果计数少于3,它只是将应用程序发送回后台(暂停应用程序并使用户返回启动前运行的状态)。我检查的屏幕少于3个,因为我只有一个简介屏幕。另外,我检查了计数,因为我的应用程序允许用户通过菜单导航回到主屏幕,因此,如果堆栈中除了介绍屏幕以外的活动,就可以像平常一样通过其他屏幕进行备份。

//We want the home screen to behave like the bottom of the activity stack so we do not return to the initial screen
//unless the application has been killed. Users can toggle the session mode with a menu item at all other times.
@Override
public void onBackPressed() {
    //Check the activity stack and see if it's more than two deep (initial screen and home screen)
    //If it's more than two deep, then let the app proccess the press
    ActivityManager am = (ActivityManager)this.getSystemService(Activity.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasks = am.getRunningTasks(3); //3 because we have to give it something. This is an arbitrary number
    int activityCount = tasks.get(0).numActivities;

    if (activityCount < 3)
    {
        moveTaskToBack(true);
    }
    else
    {
        super.onBackPressed();
    }
}

7

在清单中,您可以添加:

android:noHistory="true"

<activity
android:name=".ActivityName"
android:noHistory="true" />

你也可以打电话

finish()

调用startActivity(..)后立即


2
使用活动标志比将内容放入清单更好。
Trevor Hart


4

没人提到这种优雅的解决方案真是太疯狂了。这应该是公认的答案。

SplashActivity -> AuthActivity -> DashActivity

if (!sessionManager.isLoggedIn()) {
    Intent intent = new Intent(context, AuthActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
    context.startActivity(intent);
    finish();
} else {
   Intent intent = new Intent(context, DashActivity.class);
   context.startActivity(intent);
    finish();
}

这里的关键是intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); 用于中介Activity。一旦该中间链接断开,DashActivity遗嘱将成为堆栈中的第一个和最后一个。

android:noHistory="true"这是一个不好的解决方案,因为当依赖于Activity回调时会引起问题,例如onActivityResult。这是推荐的解决方案,应该接受。


1
那个旗听起来太好了,以至于无法实现。FLAG_ACTIVITY_NO_HISTORY可以很好地工作,并且可以像人们期望的那样,直到将应用置于后台,然后再次置于前台,同时将带有标志的活动置于堆栈顶部。当进入后台时,该活动被破坏。返回应用程序后,您将看到堆栈中的上一个活动。我绝对不想要这样的行为。
NeverwinterMoon,

4

为时已晚,但希望对您有所帮助。大多数答案都没有指向正确的方向。对于这种事情有两个简单的标志。

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

从Android文档:

公共静态最终int FLAG_ACTIVITY_CLEAR_TASK在API级别11中添加

If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the

活动开始之前要清除的活动。也就是说,该活动成为原本为空的任务的新根,并且所有旧活动都已完成。只能与FLAG_ACTIVITY_NEW_TASK结合使用。


1

像这样在startActivity(intent)之前调用this.finish()-

       Intent intent = new Intent(ActivityOne.this, ActivityTwo.class);
        this.finish();
        startActivity(intent);

对“此”有错误的用户,应将其更改为“ ActivityOne.this”
ninbit

1

从历史记录中删除活动是通过在不需要的活动之前设置标志来完成的

A-> B-> C-> D

假设A,B,C和D是4个活动,如果要清除B和C,则设置标志

intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

在活动A和B中

这是代码位

Intent intent = new Intent(this,Activity_B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);

0
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            super.finishAndRemoveTask();
        }
        else {
            super.finish();
        }

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.