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說明吧!

 

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

 

  1. Force finish another activity that you had previously started with startActivityForResult(Intent, int).  
  2. Parameters  

還有,下面兩個方法,可以參閱文檔以及源碼研究一下。

 

 

  1. finishActivityFromChild(Activity child, int requestCode)  
  2. finishFromChild(Activity child)  

 

2. killProcess

通過調用 android.os.Process 的相關方法,結束 App,示例如下:

 

  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) 方法可以退出程序,通過查看該方法源碼,知道它實際上是調用下面的方法:

 

  1. Runtime.getRuntime().exit(code);  
 

 

示例代碼,如下所示:

 

  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說明:

 

  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這個類的該方法源碼:

 

  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說明:

 

 

  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()方法。

  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()是一個本地方法:

 

 

  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方法

  1. ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);      
  2. manager.restartPackage(getPackageName());  

 

首先需要創建ActivityManager對象,然後調用restartPackage()方法(如果有興趣的話,可以看源碼)。

注意:getPackageName獲得當前應用包名稱,如mark.zhang

使用這種方式來退出App,需要權限:

 

  1. <uses-permission android:name="android.permission.RESTART_PACKAGES" />  

更加詳細的說明,如下:

 

  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類的下面這個方法:

 

  1. public void killBackgroundProcesses (String packageName)  

api 文檔說的很清楚:

 

 

  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.  

另外,需要使用權限:

 

 

  1. <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>   

 

但是不管你怎麼樣折騰,還是無法退出App,嗚呼哀哉!這裏給出一個方法:

 

  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的生命週期方法。如:

  1. System.exit(int);  
  2. onDestroy();  

<!--EndFragment-->


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章