转载android——彻底关闭——应用程序

一万年来谁著史,三千里外欲封侯。这篇文章主要讲述转载android——彻底关闭——应用程序相关的知识,希望能为你提供帮助。
转载自http://263229365.iteye.com/blog/1283914
最近学习做android的游戏开发时候,发现一个关于android退出时不能彻底关闭的问题,比如:一个程序里new 出了N多个Thread,这样在退出程序的可能不能完全关闭,最后发现,只用finish()方法,有时候不能彻底退出,个人感觉还是要在适当的地方加上:System.exit(0);
-=====-=-=-=-=-=======-----=====
 
1. finish()方法
该方法可以结束当前 Activity,但是如果你的App有很多 Activity 的话,使用该方法显得有点捉襟见肘了。
另外,还有一个方法finishActivity (int requestCode) ,关于这个方法,先看看sdk的api说明吧!
 
view plainprint?

  1. public  void  finishActivity  (int  requestCode)   
  2. Since:  API  Level  1   
  3. Force  finish  another  activity  that  you  had  previously  started  with  startActivityForResult(Intent,  int).   
  4. Parameters  requestCode    The  request  code  of  the  activity  that  you  had  given  to  startActivityForResult().  If  there  are  multiple  activities  started  with  this  request  code,  they  will  all  be  finished.   
 
也许你会这样理解 ,Activity1 通过方法 startActivityForResult (Intent, int) 启动 Activity2,然后在 Activity2 中通过方法finishActivity (int requestCode)来结束 Activity1,但是很不幸运,不是这样的。不信你可以Demo一把! 
上面文档说得很明白,该方法强制关闭通过方法 startActivityForResult (Intent, int) 启动的 Activity,也就是说在 Activity1 中的(重写)方法onActivityResult(int requestCode, int resultCode, Intent data) 来接收 Activity2 返回的结果,必须在  Activity1 中调用finishActivity (int requestCode)来结束 Activity2。(一般在onActivityResult 方法调用该方法结束 Activity2)。
 
view plainprint?
  1. Force  finish  another  activity  that  you  had  previously  started  with  startActivityForResult(Intent,  int).   
  2. Parameters   
还有,下面两个方法,可以参阅文档以及源码研究一下。
 
 
view plainprint?
  1. finishActivityFromChild(Activity  child,  int  requestCode)   
  2. finishFromChild(Activity  child)   
 
2.  killProcess
通过调用 android.os.Process 的相关方法,结束 App,示例如下:
 
view plainprint?
  1. btn_exit.setOnClickListener(new  Button.OnClickListener()  {   
  2.         @Override   
  3.         public  void  onClick(View  v)  {   
  4.                 android.os.Process.killProcess(android.os.Process.myPid());    
  5.         }   
  6.             });    
 
 
3. exit
我们知道,java 的 exit(int code) 方法可以退出程序,通过查看该方法源码,知道它实际上是调用下面的方法:
 
view plainprint?
  1. Runtime.getRuntime().exit(code);    
 
 
示例代码,如下所示:
 
view plainprint?
  1. btn_exit.setOnClickListener(new  Button.OnClickListener()  {   
  2.                         @Override   
  3.                         public  void  onClick(View  v)  {   
  4.                                 System.exit(0); //正常退出App   
  5.                         }   
  6.                 });    
 
 
接下来,我们研究一下这个方法。java.lang.System这个类的该方法jdk说明:
【转载android——彻底关闭——应用程序】 
view plainprint?
  1. exit   
  2.    
  3. public  static  void  exit(int  status)   
  4. 终止当前正在运行的  Java  虚拟机。参数用作状态码;根据惯例,非  0  的状态码表示异常终止。   
  5. 该方法调用  Runtime  类中的  exit  方法。该方法永远不会正常返回。   
  6.    
  7. 调用  System.exit(n)  实际上等效于调用:   
  8.    
  9.   Runtime.getRuntime().exit(n)   
  10.      
  11. 参数:   
  12. status  -  退出状态。   
  13. 抛出:   
  14. SecurityException  -  如果安全管理器存在并且其  checkExit  方法不允许以指定状态退出。   
  15. 另请参见:   
  16. Runtime.exit(int)   
也就是说,参数为非0值的话是异常退出程序。参数为0的话,就是正常退出。
 
看RunTime这个类的该方法源码:
 
view plainprint?
  1. public  void  exit(int  status)  {   
  2.                 SecurityManager  security  =  System.getSecurityManager();    
  3.         if  (security  !=  null)  {   
  4.                 security.checkExit(status);    
  5.         }   
  6.         Shutdown.exit(status);    
  7. }   
其api说明:
 
 
view plainprint?
  1. exit   
  2.    
  3. public  void  exit(int  status)   
  4. 通过启动虚拟机的关闭序列,终止当前正在运行的  Java  虚拟机。此方法从不正常返回。可以将变量作为一个状态码;根据惯例,非零的状态码表示非正常终止。   
  5. 虚拟机的关闭序列包含两个阶段。在第一个阶段中,会以某种未指定的顺序启动所有已注册的关闭钩子  (hook)(如果有的话),并且允许它们同时运行直至结束。在第二个阶段中,如果已启用退出终结,则运行所有未调用的终结方法。一旦完成这个阶段,虚拟机就会暂停。   
  6.    
  7. 如果在虚拟机已开始其关闭序列后才调用此方法,那么若正在运行关闭钩子,则将无限期地阻断此方法。如果已经运行完关闭钩子,并且已启用退出终结  (on-exit  finalization),那么此方法将利用给定的状态码(如果状态码是非零值)暂停虚拟机;否则将无限期地阻断虚拟机。   
  8.    
  9. System.exit  方法是调用此方法的一种传统而便捷的方式。   
  10.    
  11. 参数:   
  12. status  -  终止状态。按照惯例,非零的状态码表明非正常终止。   
  13. 抛出:   
  14. SecurityException  -  如果安全管理器存在,并且其  checkExit  方法不允许存在指定的状态   
  15. 另请参见:   
  16. SecurityException,  SecurityManager.checkExit(int),  addShutdownHook(java.lang.Thread),  removeShutdownHook(java.lang.Thread),  runFinalizersOnExit(boolean),  halt(int)   
该方法又是调用Shutdown这个类的exit()方法。
view plainprint?
  1. static  void  exit(int  status)  {   
  2.         boolean  runMoreFinalizers  =  false;    
  3.         synchronized  (lock)  {   
  4.                 if  (status  !=  0)  runFinalizersOnExit  =  false;    
  5.                 switch  (state)  {   
  6.                 case  RUNNING:      /*  Initiate  shutdown  */   
  7.                 state  =  HOOKS;    
  8.                 break;    
  9.                 case  HOOKS:          /*  Stall  and  halt  */   
  10.                 break;    
  11.                 case  FINALIZERS:   
  12.                 if  (status  !=  0)  {   
  13.                         /*  Halt  immediately  on  nonzero  status  */   
  14.                         halt(status);    
  15.                 }  else  {   
  16.                         /*  Compatibility  with  old  behavior: 
  17.                           *  Run  more  finalizers  and  then  halt 
  18.                           */   
  19.                         runMoreFinalizers  =  runFinalizersOnExit;    
  20.                 }   
  21.                 break;    
  22.                 }   
  23.         }   
  24.         if  (runMoreFinalizers)  {   
  25.                 runAllFinalizers();    
  26.                 halt(status);    
  27.         }   
  28.         synchronized  (Shutdown.class)  {   
  29.                 /*  Synchronize  on  the  class  object,  causing  any  other  thread 
  30.                           *  that  attempts  to  initiate  shutdown  to  stall  indefinitely 
  31.                   */   
  32.                 sequence();    
  33.                 halt(status);    
  34.         }   
  35.         }   
其中,runAllFinalizers()是一个本地方法:
 
 
view plainprint?
  1. JNIEXPORT  void  JNICALL   
  2. Java_java_lang_Shutdown_runAllFinalizers(JNIEnv  *env,  jclass  ignored)   
  3. {   
  4.         jclass  cl;    
  5.         jmethodID  mid;    
  6.    
  7.         if  ((cl  =  (*env)-> FindClass(env,  "java/lang/ref/Finalizer"))   
  8.         & &   (mid  =  (*env)-> GetStaticMethodID(env,  cl,   
  9.                                                 "runAllFinalizers",  "()V")))  {   
  10.         (*env)-> CallStaticVoidMethod(env,  cl,  mid);    
  11.         }   
  12. }   
System.exit()的参数是把退出原因返回给系统, 一般来说可以是任何的整数 。

0表示正常退出,1表示非正常 。
 
最后说一下finish()与exit方法的区别:
finish()是Activity的类方法,仅仅针对Activity,当调用finish()时,只是将活动推向后台,并没有立即释放内存,活动的资源并没有被清理;当调用System.exit(0)时,退出当前Activity并释放资源(内存),但是该方法不可以结束整个App如有多个Activty或者有其他组件service等不会结束。
其实android的机制决定了用户无法完全退出应用,当你的application最长时间没有被用过的时候,android自身会决定将application关闭了。

4. restartPackage方法
view plainprint?
  1. ActivityManager  manager  =  (ActivityManager)  getSystemService(Context.ACTIVITY_SERVICE);            
  2. manager.restartPackage(getPackageName());    
 
首先需要创建ActivityManager对象,然后调用restartPackage()方法(如果有兴趣的话,可以看源码)。
注意:getPackageName获得当前应用包名称,如mark.zhang
使用这种方式来退出App,需要权限:
 
view plainprint?
  1. < uses-permission  android:name="android.permission.RESTART_PACKAGES"  />    
更加详细的说明,如下:
 
view plainprint?
  1. void  android.app.ActivityManager.restartPackage(String  packageName)   
  2.    
  3. Have  the  system  perform  a  force  stop  of  everything  associated  with  the  given  application  package.  All  processes  that  share  its  uid  will  be  killed,  all  services  it  has  running  stopped,  all  activities  removed,  etc.  In  addition,  a  Intent.ACTION_PACKAGE_RESTARTED  broadcast  will  be  sent,  so  that  any  of  its  registered  alarms  can  be  stopped,  notifications  removed,  etc.   
  4.    
  5. You  must  hold  the  permission  android.Manifest.permission.RESTART_PACKAGES  to  be  able  to  call  this  method.   
  6.    
  7. Parameters:   
  8.         packageName  The  name  of  the  package  to  be  stopped.   
可以看出,相同的UID的进程会被kill,还会停止相关的服务以及移除所有的Activity,并且会发送一个广播。
 
注意一个问题:在android2.2之后,该方法不可以将应用程序结束,需要使用ActivityManager类的下面这个方法:
 
view plainprint?
  1. public  void  killBackgroundProcesses  (String  packageName)   
api 文档说的很清楚:
 
 
view plainprint?
  1. public  void  restartPackage  (String  packageName)   
  2.    
  3. Since:  API  Level  3   
  4. This  method  is  deprecated.   
  5. This  is  now  just  a  wrapper  for  killBackgroundProcesses(String);   the  previous  behavior  here  is  no  longer  available  to  applications  because  it  allows  them  to  break  other  applications  by  removing  their  alarms,  stopping  their  services,  etc.   
另外,需要使用权限:
 
 
view plainprint?
  1. < uses-permission  android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>      
 
但是不管你怎么样折腾,还是无法退出App,呜呼哀哉!这里给出一个方法:
 
view plainprint?
  1. int  currentVersion  =  android.os.Build.VERSION.SDK_INT;    
  2.                         if  (currentVersion  >   android.os.Build.VERSION_CODES.ECLAIR_MR1)  {   
  3.                                 Intent  startMain  =  new  Intent(Intent.ACTION_MAIN);    
  4.                                 startMain.addCategory(Intent.CATEGORY_HOME);    
  5.                                 startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);    
  6.                                 startActivity(startMain);    
  7.                                 System.exit(0);    
  8.                         }  else  {//  android2.1   
  9.                                 ActivityManager  am  =  (ActivityManager)  getSystemService(ACTIVITY_SERVICE);    
  10.                                 am.restartPackage(getPackageName());    
  11.                         }   

关于android.os.Build.VERSION.SDK_INT,可以参考  http://blog.csdn.net/androidbluetooth/article/details/6778422
 
 
5. 小结
 
finish():结束当前Activity,不会立即释放内存。遵循android内存管理机制。
 
exit():结束当前组件如Activity,并立即释放当前Activity所占资源。
 
killProcess():结束当前组件如Activity,并立即释放当前Activity所占资源。
 
restartPackage():结束整个App,包括service等其它Activity组件。
 
特别注意:除了finish()方法可以调用Activity的生命周期方法如onStop()、onDestroy(),其余三种退出App均不会调用Activity的生命周期方法。除非,在调用这几个方法之前或者之后主动调用Activity的生命周期方法。如:
 
view plainprint?
  1. System.exit(int);    
  2. onDestroy();  
< !--EndFragment-->

    推荐阅读