【问题标题】:Removing an activity from the history stack从历史堆栈中删除活动
【发布时间】:2010-12-26 07:32:06
【问题描述】:

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

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

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

当用户从活动 #2 转到 #3 时,是否可以将 #1 和 #2 从历史堆栈中完全擦除?我希望这样,如果用户在 #3 并点击后退按钮,他们只会转到主屏幕,而不是返回启动屏幕。

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

谢谢

【问题讨论】:

  • 进入主屏幕后,当用户恢复您的应用时,是否会将他带到 ActivitySplashScreen 或 ActivityGameMain?

标签: android android-activity activity-lifecycle


【解决方案1】:

您可以通过在您的AndroidManifest.xml 文件中的相关<activity> 条目中将android:noHistory attribute 设置为"true" 来实现此目的。例如:

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

【讨论】:

  • 这是最好的方法。
  • 等效地你可以使用FLAG_ACTIVITY_NO_HISTORY
  • 如何通过代码实现这一点?因为我不想一直这样做。我只想在某些情况下从历史记录中删除给定的活动。
  • 请注意,使用 noHistory 属性将使该活动完成,例如,这可能会导致 G+ 登录出现意外行为。请参阅:stackoverflow.com/questions/20383878/… 我花了一段时间才找到这个错误,因为我的应用程序一直崩溃而没有任何痕迹。
  • 需要的标志是一个链接,复制起来比较困难,所以这里可以很容易地复制。 android:noHistory="true"
【解决方案2】:

您可以在启动下一个活动时使用转发从活动堆栈中删除上一个活动。 There's an example of this in the APIDemos,但基本上你所做的只是在调用startActivity() 之后立即调用finish()

【讨论】:

  • 嗨,Daniel,我通读了这个示例,但这只会清除 1 个活动的历史堆栈,不是吗?如果我的堆栈看起来像 A、B,并且我正在启动 C,我希望 C 成为新根并完全清除 A 和 B。在 sdk 示例中,从 B 调用 finish() 会给我留下一堆 A ,C,不是吗?谢谢。
  • 您可以在启动 B 时清除 A,在启动 C 时清除 B;但是,我想如果这是您想要的,那么您将无法从 B 退出到 A。如果这是一个问题,我将不得不考虑更多。
  • 马克,要实现你想要的,你必须使用标志:FLAG_ACTIVITY_CLEAR_TOP。我希望它有所帮助。
  • FLAG_ACTIVITY_CLEAR_TOP 不起作用,因为 C 还没有在后台堆栈中。
  • @DanielLew APIDemos 中有很多例子。你有建议的例子的名字吗?
【解决方案3】:

【讨论】:

  • 请注意,这不会为您启动的活动设置历史记录。为了没有您启动的活动的历史记录,我只是在清单中将其设置为 android:noHistory="true"
  • 这很好用。使用intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) 设置此标志。
【解决方案4】:

这可能不是理想的方法。如果有人有更好的方法,我将期待实施它。以下是如何使用 pre-version-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 中的操作有条件地从堆栈中删除一个活动,这是一个很好的答案
【解决方案5】:

在 API 11 之前有效的一种方法是先启动 ActivityGameMain,然后在该 Activity 的 onCreate 中启动您的 ActivitySplashScreen Activity。 ActivityGameMain 不会出现,因为你调用 startActivity 太快了。

然后您可以在启动ActivityGameMain 时通过在 Intent 上设置这些标志来清除堆栈:

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

您还必须将其添加到 ActivitySplashScreen:

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

因此,按下该活动不会回到您的ActivityGameMain

我假设您不希望闪屏返回到任何一个,为了实现这一点,我建议在您的AndroidManifest.xml 中将其设置为noHistory。然后将 goBackPressed 代码放在您的 ActivitySplashScreenSignUp 类中。

但是我找到了一些方法来解决这个问题。在显示 ActivitySplashScreenSignUp 且返回历史记录未重置时,从通知启动另一个应用程序。

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

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);

【讨论】:

    【解决方案6】:

    我用这种方式。

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

    【讨论】:

    • 谢谢。我发现这在我的菜单中有一个主页按钮的情况下很有帮助,并且我不希望一旦用户从那里点击主页时出现堆叠的活动。
    【解决方案7】:

    我知道我迟到了(问这个问题已经两年了),但我通过拦截后退按钮来实现这一点。我没有检查特定活动,而是查看计数,如果它小于 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();
        }
    }
    

    【讨论】:

      【解决方案8】:

      您可以在清单中添加:

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

      你也可以调用

      finish()
      

      在调用 startActivity(..) 之后立即

      【讨论】:

      • 最好使用活动标志而不是把东西放在清单中。
      【解决方案9】:

      只需在 Manifest 文件中设置 noHistory="true"。 它使活动从后台删除。

      【讨论】:

        【解决方案10】:

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

        SplashActivity -&gt; AuthActivity -&gt; 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。这是推荐的解决方案,应该被接受。

        【讨论】:

        • 那个标志听起来好得令人难以置信。 FLAG_ACTIVITY_NO_HISTORY 工作得很好,正如人们所期望的那样,直到将应用程序置于后台,然后再次置于前台,同时将带有标志的活动置于堆栈顶部。进入后台时,活动被破坏。返回应用程序时,将看到堆栈中的前一个活动。我绝对不想要这样的行为。
        【解决方案11】:

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

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

        来自 Android 文档:

        public static final 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。

        【讨论】:

          【解决方案12】:

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

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

          【讨论】:

          • 对“this”有错误的用户,应将其更改为“ActivityOne.this”
          【解决方案13】:

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

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

          【讨论】:

            【解决方案14】:
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        super.finishAndRemoveTask();
                    }
                    else {
                        super.finish();
                    }
            

            【讨论】:

              【解决方案15】:

              试试这个:

              intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)

              它是 API 级别 1,检查 link

              【讨论】:

              • 这是做什么的?绝对不能解决问题。
              • 你确定不是Intent.FLAG_ACTIVITY_NO_HISTORY
              猜你喜欢
              • 1970-01-01
              • 2020-06-04
              • 2013-08-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-12-16
              相关资源
              最近更新 更多