【问题标题】:How to check if an activity is the last one in the activity stack for an application?如何检查一个活动是否是应用程序活动堆栈中的最后一个活动?
【发布时间】:2011-08-23 23:10:44
【问题描述】:

我想知道如果用户退出当前活动,他是否会返回主屏幕。

【问题讨论】:

标签: android android-activity lifecycle


【解决方案1】:

我将把@H9kDroid 的评论贴在这里,作为有类似问题的人的最佳答案。

您可以使用isTaskRoot() 来了解活动是否是任务的根。

希望对你有帮助

【讨论】:

  • 能否请您提供单行代码,以便清楚如何使用isTaskRoot。谢谢。
  • @TheHunter if (isTaskRoot()) { // do something }
  • 唯一的问题是在 = 5.x 不同。它似乎总是返回 false。
  • 我认为您应该考虑将 cmets 中提供的示例代码合并到答案中,以方便将来的读者使用。
  • 优秀的答案。在我的情况下,用户单击通知后,如果他们之前关闭应用程序,则活动可能是根
【解决方案2】:

更新(2015 年 7 月):

由于 getRunningTasks() 已被弃用,从 API 21 开始,最好遵循 raukodraug answerEd Burnette one(我更喜欢第二个)。


可以使用ActivityManager 检查当前任务及其堆栈。

所以,要确定一个活动是否是最后一个:

  • 在清单中请求 android.permission.GET_TASKS 权限。
  • 使用以下代码:

    ActivityManager mngr = (ActivityManager) getSystemService( ACTIVITY_SERVICE );
    
    List<ActivityManager.RunningTaskInfo> taskList = mngr.getRunningTasks(10);
    
    if(taskList.get(0).numActivities == 1 &&
       taskList.get(0).topActivity.getClassName().equals(this.getClass().getName())) {
        Log.i(TAG, "This is last activity in the stack");
    }
    

请注意,上述代码仅在您有单个任务时才有效。如果您的应用程序可能存在多个任务 - 您需要检查其他 taskList 元素。阅读更多关于任务Tasks and Back Stack


【讨论】:

  • H9kDroid 提出了正确的建议。选择的答案是 hack。应该使用isTaskRoot() 方法以正确的方式进行操作。
  • @Sufian 它在哪里特别破解?该代码是合乎逻辑的,并以它们打算使用的方式使用开放的 android API(例如,getRunningTasks 应该用于获取正在运行的任务,并且可能只想为了分析这些任务而调用它)。 get(0) 的用法有据可查且符合逻辑“返回当前正在运行的任务的列表,最近的任务是第一个,之后是较旧的任务”。
  • getRunningTasks() 在 API 级别 21 中已弃用。
  • 我可以对片段做同样的事情吗?如果是,那怎么办?请帮忙
  • @Mr.Drew 查看来自@raukodraug 的最高投票答案
【解决方案3】:

希望这将有助于新的初学者,基于上面的答案对我来说很好,我也分享代码 sn-p 所以它很容易实现。

解决方案:我使用了isTaskRoot(),如果当前活动只是你的堆栈中的活动,我会返回 true 并且除了我还处理案例如果我在堆栈中有一些活动,请转到堆栈中的最后一个活动,而不是打开新的自定义活动。

在你的活动中

   @Override
    public void onBackPressed() {

        if(isTaskRoot()){
            startActivity(new Intent(currentActivityName.this,ActivityNameYouWantToOpen.class));
            // using finish() is optional, use it if you do not want to keep currentActivity in stack
            finish();
        }else{
            super.onBackPressed();
        }

    }

【讨论】:

    【解决方案4】:

    有一个最简单的解决方案,你可以使用isTaskRoot() 在你的活动中

    【讨论】:

      【解决方案5】:

      跟踪这一点的一种方法是在您开始新活动时包含一个标记并检查该标记是否存在。

      每当您开始一项新活动时,插入标记:

      newIntent=new Intent(this, NextOne.class);
      newIntent.putExtra(this.getPackageName()+"myself", 0);
      startActivity(newIntent);
      

      然后你可以像这样检查它:

      boolean islast=!getIntent().hasExtra(this.getPackageName()+"myself")
      

      【讨论】:

      • 如果活动被杀死并且活动堆栈被重建 - 每个活动都按需求进行,则不起作用。
      【解决方案6】:

      虽然可能有办法实现这一点(请参阅其他答案),但我建议您不要这样做。普通的 Android 应用程序不需要知道主屏幕是否即将显示。

      如果您要保存数据,请将数据保存代码放在您的 onPause() 方法中。如果您试图让用户改变他们对现有应用程序的看法,您可以拦截 Back 键和 onBackPressed() 方法的向上/向下键,并向他们显示“您确定吗?”提示。

      【讨论】:

      • 如果我需要一个服务在用户没有离开活动的情况下运行呢?我无法捕获任何像 onStop 这样的函数,因为这些函数可以在屏幕关闭后调用。
      • 如果后台服务启动了一个 Activity,也许你想知道它是否是栈上唯一的 Activity。
      【解决方案7】:

      我为我的所有活动创建了一个基类,扩展了 AppCompatActivity,它有一个静态计数器:

      public abstract class BasicActivity extends AppCompatActivity {
          private static int activityCounter = 0;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              ++activityCounter;
              ...
          }
      
          @Override
          public void onDestroy() {
              super.onDestroy();
              --activityCounter;
              if(activityCounter==0) {
                  // Last instance code...
              }
          }
      
          public boolean isLastInstance() { return (activityCounter==1); }
      }
      

      到目前为止,这已经足够好了;并且无论 API 版本如何。当然,它要求所有活动都扩展这个基类——在我的例子中,它们就是这样做的。

      编辑:我注意到在应用程序完全退出之前计数器降为零的情况,即方向改变并且只有一个活动打开的情况。当方向改变时,该活动关闭并创建另一个活动,因此为最后一个活动调用onDestroyed,然后在使用更改的方向创建相同活动时调用onCreate。必须考虑这种行为; OrientationEventListener 可能会被使用。

      【讨论】:

        【解决方案8】:

        sandrstar 使用ActivityManager 的解决方案的问题是:您需要获得权限才能以这种方式获取任务。 我找到了更好的方法:

        getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)
        

        Stack 底部的Activity 应该总是默认获取该类别,而其他活动不应该获取它。
        但即使这在某些设备上失败,您也可以在启动 Activity 时进行设置:

        Intent intent = new Intent(startingActivity, SomeActivityClass.class);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        activity.startActivity(intent);
        

        【讨论】:

        • 如果活动是从推送通知中打开的呢?他们没有 CATEGORY LAUNCHER
        • 我很确定我的答案的第二部分仍然适用。您可以将类别设置为意图中的提示。在这种情况下,可能是您的通知上下文的意图。除此之外,您还可以为此使用标志。请参阅此链接以创建有意图的通知:stackoverflow.com/questions/13716723/…
        • 仍然,如果您最旧的活动是 MainActivity,现在它已恢复,然后您收到推送通知并将pendingIntent 设置为使用 CATEGORY_LAUNCHER 打开,那么您将有 2 个此类活动。不过可能在不同的任务上
        • 我不确定它是如何处理通知的。我从来没有像你在这里那样使用它们。我很确定有一种简单的方法可以使用这种方法,但自 2014 年第一季度以来我没有接触过 android 代码。也许你想在这种情况下使用第二类?还是什么旗帜?但我想它的精神是这样工作的。那么启动主要活动并添加某种元信息以打开正确的活动怎么样?
        【解决方案9】:

        Android 实现了一个 Activity 堆栈,我建议你阅读它here。看起来您想要做的只是检索调用活动:getCallingActivity()。如果当前活动是您的应用程序中的第一个活动,并且应用程序是从主屏幕启动的,它应该(我假设)返回 null

        【讨论】:

        • 这不起作用,因为如果活动不是通过 startActivityForResult() 启动的,getCallingActivity() 将返回 null。
        【解决方案10】:

        这里错过的一件事是“主页键”单击,当激活时,您无法从活动中检测到这一点,因此最好通过处理“返回键”按下并移动到以编程方式控制活动堆栈必要的活动或只是做必要的步骤。

        此外,您不能确定是否可以通过将一些额外数据预设为打开活动的意图来检测从“最近活动”列表启动活动,因为在这种情况下会重复使用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-03-12
          • 1970-01-01
          • 2014-01-30
          • 1970-01-01
          • 2012-12-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多