【问题标题】:Close application and launch home screen on Android关闭应用程序并在 Android 上启动主屏幕
【发布时间】:2011-01-03 18:35:40
【问题描述】:

我有两个不同的活动。第一个启动第二个。在第二个活动中,我调用System.exit(0) 以强制关闭应用程序,但第一个活动会自动显示,而不是应用程序返回主屏幕。如何避免这种情况,并让应用程序返回主屏幕?

【问题讨论】:

  • 因为Stack中有多个Activity,所以System.exit(?)会重启它。 (我认为)

标签: android android-activity


【解决方案1】:

简答:调用moveTaskToBack(true) on your Activity 而不是System.exit()。这将隐藏您的应用程序,直到用户想要再次使用它。

更长的答案从另一个问题开始:你为什么要杀死你的应用程序?

Android 操作系统处理内存管理和进程等,所以我的建议是让 Android 为您担心这些。如果用户想离开您的应用程序,他们可以按 Home 按钮,您的应用程序将有效地消失。如果手机稍后需要更多内存,那么操作系统将终止您的应用程序。

只要您是responding to lifecycle events appropriately,您和用户都不需要关心您的应用程序是否仍在运行。

所以如果你想隐藏你的应用程序调用moveTaskToBack() 并让 Android 决定何时终止它。

【讨论】:

  • 有关 Dave 论点的更多信息,请查看stackoverflow.com/questions/2033914/…
  • 杀死应用程序有合法用途 - 例如,我正在制作封闭测试版,如果用户没有适当的密码,则需要关闭我的应用程序。
  • @Matt:你为什么不在密码屏幕上阻止用户呢?如果他们不能超过那个点,那你为什么需要强制关闭应用程序?
  • 一种特殊情况是用户按下后退按钮退出应用程序。在这种情况下,默认的 onKeyUp() 处理程序会执行 finish()。但我的经验是,finish() 并不总是能充分清理内存,而 System.exit(0) 则可以。因此,在用户基本上与您的应用程序说再见并暗示她不想保留任何状态的特定情况下,我发现调用 System.exit(0) 在清理方面做得更好起来。
【解决方案2】:

下面给出了实现这一点的最简单方法(不影响 Android 的本机内存管理。不涉及进程终止)。

  1. 使用这个 Intent 启动一个活动:

    Intent intent = new Intent(this, FinActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    startActivity(intent);
    finish();
    
  2. 在目标活动FinActivity.class中,调用onCreate中的finish()。

步骤说明:

  1. 您创建一个意图删除所有其他活动(FLAG_ACTIVITY_CLEAR_TOP) 并删除当前活动。

  2. 活动会自行销毁。另一种方法是您可以在 finActivity 中制作启动画面。这是可选的。

【讨论】:

  • 你不希望 startActivity() 在 finish() 之前吗?
  • FinActivity 必须是您的 RootActivity 对吗?使用此标志将重新启动您的 FinActivity.class,如文档 developer.android.com/reference/android/content/… 中所述,我在下面的答案中提供了一个示例来克服这个问题。
  • 像魅力一样工作:)
  • 这确实退出了活动和服务,但调试器仍然显示在后台运行的线程,它仍然显示我的应用程序正在按下多任务按钮。
【解决方案3】:

您真的应该考虑不退出应用程序。这不是 Android 应用程序通常的工作方式。

【讨论】:

  • 因为在安卓应用中没有退出。有没有一种方法可以遍历应用程序的所有活动,以便我在每个活动上调用 Finish(),即完成所有已开始的活动?
  • 为什么需要这样做?活动是否因为您已注销或其他情况而处于不正确状态?您可以在 onResumefinish 活动中检查这一点。
  • 问题在于,作为用户和开发人员,Android 中的自动内存清理功能并不那么好。那里有太多“行为不端”的应用程序,以至于我的手机确实开始耗尽内存,当它变低时,用户界面开始结结巴巴。这是一个相对较高的规格(这次)HTC Desire。我想这就是我和其他人有时会问这个问题的原因。
  • @Richard:在您的应用程序上调用 onPause 时停止所有活动不是更好的解决方案吗?应用程序导致速度变慢的唯一方法是,如果您在不需要时暂停时仍然运行 AsyncTasks 等。例如,游戏应该在 onPause 之后退出它们的主循环。 (并且提前退出循环不算在内。)
  • @pydave:我同意你的看法。但是关于这类话题似乎有很多争论,我正在分享一些“真实世界”的开发和用户体验。事实是,随着可用内存的减少,我的手机速度明显变慢。可以这么说,我似乎有“在后台”的应用程序,这些应用程序正在耗尽内存。如果我杀死这些应用程序,我会体验到我的设备会加速。这让我认为,如果 1) 开发人员可以编写代码来完全杀死一个进程并释放其内存,或者 2) android GC 运行得比现在好一点,那就太好了。 ymmv
【解决方案4】:

Android 有一种机制可以根据其文档安全地关闭应用程序。在退出的最后一个 Activity(通常是应用程序启动时首先出现的主 Activity)中,只需在 onDestroy() 方法中放置几行。对 System.runFinalizersOnExit(true) 的调用可确保在应用程序退出时所有对象都将被终结并被垃圾回收。例如:

public void onDestroy() {
    super.onDestroy();

    /*
     * Notify the system to finalize and collect all objects of the
     * application on exit so that the process running the application can
     * be killed by the system without causing issues. NOTE: If this is set
     * to true then the process will not be killed until all of its threads
     * have closed.
     */
    System.runFinalizersOnExit(true);

    /*
     * Force the system to close the application down completely instead of
     * retaining it in the background. The process that runs the application
     * will be killed. The application will be completely created as a new
     * application in a new process if the user starts the application
     * again.
     */
    System.exit(0);
}

最后Android不会通知应用程序HOME键事件,所以当HOME键被按下时你不能关闭应用程序。 Android 将 HOME 键事件保留给自己,以便开发人员无法阻止用户离开他们的应用程序。

【讨论】:

  • 看AOSP源码,这个方法现在已经被弃用了:@deprecated 这个方法是不安全的。
【解决方案5】:

您还可以在第一个活动的标签中指定noHistory = "true" 或在您开始第二个活动后立即完成第一个活动(如大卫所说)。

AFAIK,“强制关闭”会终止托管您的应用程序运行的 JVM 的进程,并且 System.exit() 终止运行应用程序实例的 JVM。两者都是突然终止的形式,不建议用于正常的应用程序流程。

正如捕获异常以覆盖程序可能执行的逻辑流一样,不建议这样做。

【讨论】:

  • 无法正确关闭应用程序而所有活动仍然打开?
  • 不,Android 中没有真正的“应用程序”概念;您的应用程序是活动的集合。如果您不想在完成第二个活动后返回第一个活动,那么您应该使用前面提到的noHistory 属性。
【解决方案6】:

我用这个方法关闭Activity!

public static void closeAllBelowActivities(Activity current) {
    boolean flag = true;
    Activity below = current.getParent();
    if (below == null)
        return;
    System.out.println("Below Parent: " + below.getClass());
    while (flag) {
        Activity temp = below;
        try {
            below = temp.getParent();
            temp.finish();
        } catch (Exception e) {
            flag = false;
        }
    }
}

【讨论】:

    【解决方案7】:

    当您启动第二个活动时,finish() 第一个活动立即:

    startActivity(new Intent(...));
    finish();
    

    【讨论】:

    • 我不想系统地完成第一个活动,除非我调用 System.exit(0)。这是正常功能吗?应用程序管理器中的强制关闭按钮是如何工作的?
    • 哦。那我看错了你的问题,对不起。这不是标准 android 应用程序生命周期的样子。 FC 按钮使用类似android.os.Process.killProcess(android.os.Process.myPid()); 的东西,这不是您通常希望应用程序退出的方式。但您可能会使用它,或者您可能会考虑查看startActivityForResultfinishActivity,并构建仅当第二个活动以特定响应代码完成时第一个活动完成的东西。
    【解决方案8】:

    android.os.Process.killProcess(android.os.Process.myPid()); 工作正常,但建议让Android平台操心内存管理:-)

    【讨论】:

      【解决方案9】:

      你不能做 System.exit(),它不安全。

      您可以这样做: Process.killProcess(Process.myPid());

      【讨论】:

      • 你需要正确的权限 -
      • 适用于我的应用程序,它以设备所有者身份运行。不需要新的权限。仍然离开的是多任务视图。
      【解决方案10】:

      我用这个:

      1) 父activity调用辅助activity,方法为“startActivityForResult”

      2) 正在关闭的辅助活动中:

      int exitCode = 1; // Select the number you want
      setResult(exitCode);
      finish();
      

      3) 并在父activity中重写方法“onActivityResult”:

      public void onActivityResult(int requestCode, int resultCode, Intent data) {
          super.onActivityResult(requestCode, resultCode, data);
          int exitCode = 1;
          if(resultCode == exitCode) {
              super.setResult(exitCode); // use this if you have more than 2 activities
              finish();
          }
      }
      

      这对我来说很好。

      【讨论】:

        【解决方案11】:

        使用finish 方法。这是更简单、更容易的方法。

        this.finish();
        

        【讨论】:

          【解决方案12】:

          请记住,在处理使用持久套接字连接的应用程序时,finish() 方法不会释放连接。在正常情况下,finish() 是最好的选择,但如果您绝对需要退出应用程序并释放它正在使用的所有资源,请使用killProcess。我使用它没有任何问题。

          【讨论】:

            【解决方案13】:

            使用 startActivityForResult 启动第二个活动,并在第二个活动中返回一个值,一旦在第一个活动的 onActivityResult 方法中关闭主应用程序。我认为这是 Android 的正确做法。

            【讨论】:

              【解决方案14】:

              你错了。有一种方法可以杀死应用程序。在具有超类 Application 的类中,我们使用一些字段,例如,killApp。当我们在onResume() 中启动启动画面(第一个活动)时,我们为字段killApp 设置了一个参数为false。在最后调用onResume() 时,我们进行的每个活动中,我们都会调用类似的内容:

              if(AppClass.killApp())
                  finish();
              

              进入屏幕的每个活动都必须调用onResume()。当它被调用时,我们必须检查我们的字段killApp 是否为真。如果是真的,当前活动调用finish()。为了调用完整的动作,我们使用下一个构造。例如,在按钮的操作中:

              AppClass.setkillApplication(true);
                 finish();
                 return;
              

              【讨论】:

              • 根据文档,android系统不会杀死onStart()、onRestart()和onResume()等状态的活动。你的建议是绝对错误的!
              【解决方案15】:

              试试下面的。它对我有用。

              ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
              List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1); 
              ComponentName componentInfo = taskInfo.get(0).topActivity;
              am.restartPackage(componentInfo.getPackageName());
              

              【讨论】:

                【解决方案16】:

                假设您有像 A>B>C>D>E 这样的活动堆栈。你在活动 D,你想关闭你的应用程序。这就是你要做的 -

                在要关闭的活动中(活动 D)-

                Intent intent = new Intent(D.this,A.class);
                intent.putExtra("exit", "exit");
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_SINGLE_TOP);
                startActivity(intent);
                

                在你的 RootActivity 中(即你的基础活动,这里是 Activity A) -

                @Override
                    protected void onNewIntent(Intent intent) {
                        super.onNewIntent(intent);
                        if (intent.hasExtra("exit")) {
                            setIntent(intent);
                        }
                    }
                
                    @Override
                    protected void onResume() {
                        super.onResume();
                        if (getIntent() != null) {
                            if (("exit").equalsIgnoreCase(getIntent().getStringExtra(("exit")))) {
                                onBackPressed();
                            }
                        }
                    }
                

                使用 onNewIntent 是因为如果活动还活着,它将获得启动它的第一个意图。不是新的。 更多详情 - Documentation

                【讨论】:

                  【解决方案17】:

                  其实很简单。

                  我这样做的方法是将标志保存在一个可供所有人使用的静态变量中。然后,当我退出时,我设置了这个标志,我的所有活动都会检查这个标志onResume。如果设置了标志,那么我会在该活动上发出System.exit

                  这样,所有活动都会检查标志,如果设置了标志,则会正常关闭。

                  【讨论】:

                    【解决方案18】:

                    这是我关闭应用程序的操作: 在我的应用程序中,我有一个基本活动类,我添加了一个名为“applicationShutDown”的静态标志。 当我需要关闭应用程序时,我将其设置为 true。

                    在调用超级调用后的基础活动 onCreate 和 onResume 中,我测试了这个标志。 如果“applicationShutDown”为真,我会在当前 Activity 上调用完成。

                    这对我有用:

                    protected void onResume() {
                        super.onResume();
                        if(BaseActivity.shutDownApp)
                        {
                            finish();
                            return;
                    
                        }}
                    

                    【讨论】:

                      【解决方案19】:

                      使用 start Activity 运行第二个 Activity 以获取结果:

                      Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                      
                      //This line is important
                      intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                      
                      startActivityForResult(intent, REQUEST_CODE);
                      

                      将此函数添加到第一个Activity:

                      @Override
                      public void onActivityResult(int requestCode, int resultCode, Intent data) {
                          super.onActivityResult(requestCode, resultCode, data);
                          if(rquestCode == REQUEST_CODE)
                              if(resultCode == RESULT_CANCELED)
                                  finish();
                      }
                      

                      并将其添加到第二个 Activity:

                      @Override
                      public boolean onKeyDown(int keyCode, KeyEvent event)  {
                          if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
                      
                              Log.i(TAG, "Back key pressed");
                              setResult(RESULT_CANCELED);
                              finish();
                              return true;
                          }
                          return super.onKeyDown(keyCode, event);
                      }
                      

                      【讨论】:

                        【解决方案20】:

                        不推荐,但你仍然可以使用它。如果您需要退出应用程序,最好使用此解决方案。

                        在我看来,最好的解决方案是完成您应用中的所有活动,如下所示。

                        步骤 1. 在 mainactivity 中维护一个静态变量。说,

                        public static boolean isQuit = false;
                        

                        第 2 步。在按钮的单击事件中,将此变量设置为 true。

                        mainactivity.isQuit = true;
                        finish();
                        

                        第 3 步。在您的应用程序的每个活动中,使用如下onrestart 方法。

                        @Override
                        protected void onRestart() {
                            // TODO Auto-generated method stub
                            super.onRestart();
                            if(mainactivity.isQuit)
                                finish();
                        }
                        

                        【讨论】:

                          【解决方案21】:

                          我解决了一个类似的问题:MainActivity 启动 BrowserActivity,当用户在 BrowserActivity 中按下 Back 时,我需要关闭应用程序 - 而不是在 MainActivity 中返回。所以,在 MainActivity 中:

                          public class MainActivity extends AppCompatActivity {
                              private static final String TAG = "sm500_Rmt.MainActivity";
                              private boolean m_IsBrowserStarted = false;
                          

                          然后,在 OnResume 中:

                              @Override
                          protected void onResume() {
                              super.onResume();
                              if(m_IsBrowserStarted) {
                                  Log.w(TAG, "onResume, but it's return from browser, just exit!");
                                  finish();
                                  return;
                              }
                              Log.w(TAG, "onResume");
                          

                          ... 然后继续 OnResume。并且,当启动 BrowserActivity 时:

                              Intent intent = new Intent(this, BrowserActivity.class);
                              intent.putExtra(getString(R.string.IPAddr), ip);
                              startActivity(intent);
                              m_IsBrowserStarted = true;
                          

                          而且看起来效果不错! :-)

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2013-10-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2012-03-04
                            • 2014-09-10
                            • 1970-01-01
                            相关资源
                            最近更新 更多