清除整个历史记录堆栈并在Android上开始新的活动


332

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

情况

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

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

笔记

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

Answers:


658

在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标志来清除任务。因此,您也可以支持API之前的11级。


23
只是为了澄清一下,请使用:intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
user123321

2
如果没有Intent.FLAG_ACTIVITY_NEW_TASK,应用有时会在android 4上自行关闭
max4ever 2012年

22
IntentCompat现在有一个标志,明确任务为好,这样你就可以支持预API级别11 - developer.android.com/reference/android/support/v4/content/...
本·皮尔逊

10
IntentCompat.FLAG_ACTIVITY_CLEAR_TASK是与API级别<10的设备忽略developer.android.com/reference/android/support/v4/content/...
大卫

7
IntentCompat的标志只是为了避免崩溃,而不执行@David所说的任何操作。
Sloy

49

情况1:仅活动A和B:

这里的活动流是A-> B。单击B上的后退按钮时,我们需要关闭应用程序,然后从A启动Activity B时只需调用finish(),这将防止android将Activity A存储到Backstack中。例如,对于Activity 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.FLAG_ACTIVITY_CLEAR_TOP和Intent.FLAG_ACTIVITY_NEW_TASK会清除堆栈并将其设置为顶层,因此活动B将从堆栈而不是新实例开始。因此,当我们按返回按钮时,整个应用程序将终止。


2
这对我有用。我在所有活动中都添加了这些标志。在这些活动中,后退按钮可以完美地转到上一个活动,而在主活动中,具有Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); 完(); 整个应用已关闭,仍在内存中,但未激活,如果您重新启动,则该应用将进入初始屏幕:)
Rako

这应该是最好的答案。如果有人对我有相同的情况:A-> B-> C-> D-> E->(B)从E-> B应该有结果:A-> B
Shem Alexis Chavez

39

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

该方法适用于> = API 16。

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

1
这样就成功了,这些标志对我来说在4.xx上不起作用,而且效果很好!谢谢
乔纳森·阿斯特

1
如果您的目标是完成下面的所有活动(包括当前活动)并在自己的任务中开始新的活动,那么这似乎是正确的答案。
ToBe '18

24

我也花了几个小时...并同意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();
}

1
您是说CLEAR_TASK而不是CLEAR_TOP?
安迪

14

您不应该更改堆栈。Android后退按钮应该可以在网络浏览器中使用。

我可以想到一种方法,但这确实是一个hack。

  • 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()从堆栈中移出。

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


最后,我决定保留Stack不变,只是告诉用户他们当前的屏幕无效
Casebash 2010年

1
非常令人沮丧的是android不允许我们已经以这种方式管理活动堆栈。我很想在未来的android应用程序中使用此解决方案。
Cephron

4
为了明确为什么不应该使用它:这是创建内存泄漏的好方法。在某些时候,操作系统可能决定终止后台活动,但是由于Application采用了它们的实例,因此操作系统将无法从破坏的活动中释放剩余的RAM。
Vit Khudenko

@Arhimed还有其他问题吗?可以通过仅保留弱引用来弥补内存泄漏。
纳文2014年

1
@Navin是的,使用弱引用可以避免泄漏,但是如果在GC之后将没有活动的Activity引用,则整个方法将无用。再一次-不要这样做,这对于Android是错误的方法。
维特·胡登科

12

开始新活动后,请立即使用startActivity进行调用,以确保finish()当前活动不会堆积在新活动之后。


+1不错的解决方案,可以防止在特定情况下仅将一项活动放到历史记录堆栈中。
marsbear 2012年

27
如果你有一个以上的活动在堆栈中的终点只会清除以前的活动,但不是别人....不工作
Necronet

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

4

高级可重复使用的Kotlin:

您可以使用setter方法直接设置标志。在Kotlin中,or是按位Java或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
}


2

试试下面的代码,

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

如果正在使用像这样的活动,则再次更新api,但以前所有的statck都将被清除
Harsha

2

对我来说,没有上述方法不工作。

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

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

-1

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


1
有时您的Android模拟器可能无法连接Eclipse DDMS工具,并要求adb手动启动。在这种情况下,您可以使用命令提示符启动或停止adb。意图i =新意图(OldActivity.this,NewActivity.class); //设置新任务并清除标志i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)startActivity(i);
RajeshkumarG '16

-2

我发现太简单的hack只是这样做 AndroidManifest

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

android:noHistory会从堆栈清除有害的活动。


2
如果您在本活动中要求许可,此方法可能会在Android 6.0+上引起问题。
Vitaliy A
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.