System.exit和Process.killProcess

首先,在android中一個進程對應一個dalvik vm 實例,一個應用可以有一到多個進程,也就是對應一到多個dalvik vm instance。

一個應用可以有一到多個Task,每個Task 裏面可以有一到多個TaskRecord。每個TaskRecord 對應了一個Activity。

OK,再來看一下api 文檔時如何解釋這兩個方法的:

System.exit(code) 
Causes the VM to stop running and the program to exit with the given exit status. If runFinalizersOnExit(boolean) has been previously invoked with a true argument, then all objects will be properly garbage-collected and finalized first.

Process.killProcess(pid)
Kill the process with the given PID. Note that, though this API allows us to request to kill any process based on its PID, the kernel will still impose standard restrictions on which PIDs you are actually able to kill. Typically this means only the process running the caller's packages/application and any additional processes created by that app; packages sharing a common UID will also be able to kill each other's processes.

一個是Stop VM,一個是Kill Process,上面說了一個 進程對應一個 VM ,那麼不管是調用哪一個方法都會用看到同樣的效果。


當我們在代碼中,調用System.exit 或者 Process.KillProcess 的時候,肯定會結束掉當前線程,但是會不會重啓應用,就要根據你調用結束時,整個屬於這個應用的所有Task的狀態來決定:
android中Task 是可以跨進程跨應用的,即不同應用的activity 可能運行在同一個Task  中,System.exit 或者 Process.KillProcess 是根據什麼來決定是否重啓呢?重啓的時候又是回到的哪一個界面(Activity)的呢?哪些界面會被重啓?哪些又不會被重啓呢?分爲以下幾部來說明:

1:首先:
在每一個時刻Android 系統都有一個Task 列表,維護了當前系統中已啓動的應用以及應用中各個界面(Activity)之間的順序。比如:
Task 1 (App 1)
--- task Record 1 (Activity A) 棧頂
--- task Record 2 (Activity B)棧底
Task 11(App 1)
--- task Record 1 (Activity c)
--- task Record 2 (Activity d)
Task 2(App 2)
--- task Record 1 (Activity A)
--- task Record 2 (Activity B)
Task 2(App 3)
--- task Record 1 (Activity C)
--- task Record 2 (Activity D)

Task 有順序,TaskRecord 也是有順序的,假如當前Task 如上所說,那麼,當前手機顯示的就是 App 1 這個應用程序的 Activity A界面。

2:是否重啓:
當調用System.exit 或者 Process.KillProcess 的時候,首先會結束掉執行該方法所在的進程,然後根據結束掉該應用的時候的該應用的所有Task 狀態來決定是否重啓, 如果退出時該應用所有Task 中的TaskRecord 數量大於一 就會重啓,小於或等於一不會重啓,整個應用就結束掉了。

3:重啓後回到哪一個界面:
重啓後,會回到該應用的最上一個Task,即當前顯示的Task(因爲一個應用可以有多個Task)中,棧頂的第二個TaskRecord(棧頂第一個將不會被重啓),這也說明了爲什麼需要所有TaskRecord 的數量大於一的原因。

4:哪些會被重啓,哪些不會?
上面第二條說了,會回到第一個Task 的棧中的第二個TaskRecord,如果棧中在第二個下面還有其他TaskRecord 。那麼在按返回鍵的時候,會重新執行下一個TaskRecord 對應Activity  的onCreate 方法,依次類推,直到棧底爲止。

注意: 如果在Activity 的生命週期中執行System.exit 或者 Process.KillProcess 方法,一定要注意,在OnCreate ,OnStart,OnResume 的時候,棧中是還沒有存在該Activity對應的TaskRecord (該Activity還未被添加進去),或者同樣在OnPause,OnStop,onDestory 的時候,如果是按Back,那麼該Activity  對應的TaskRecord,在執行System.exit 或者 Process.KillProcess 之前,就已經被移除棧了,即在這種情況下,會重啓回到這個Activity 的上一個的上一個Activity(如果存在的話,如果不存在着直接退出了整個程序)。


舉例 1:
1:假如有一個App A ,  有3個Activity :ActivityA,ActivityB,ActivityC。啓動順序爲A 啓動B ,B啓動C。
2:首先通過Launcher 啓動了A 。如果在A中通過某個點擊事件,或者在A的OnCreate or onStart  or onResume 方法,或者再A中按返回鍵的時候,在OnStop or OnPause or OnDestroy 中,觸發了System.exit 或者 Process.KillProcess,那麼程序將不會重啓。
3:如果 在A中啓動了B ,並且A沒有調用finish 方法,那麼如果在B中的OnCreate or onStart  or onResume 方法,或者再B中按返回鍵的時候,在OnStop or OnPause or OnDestroy 中,觸發了System.exit 或者 Process.KillProcess,那麼程序也將不會重啓,只有當B 啓動完成,對應的TaskRecord 已經添加的Task 中了纔會重啓回到ActivityA。
4:如果在B 中啓動了C ,並且B 沒有調用finish 方法,那麼如果在C中的OnCreate or onStart  or onResume 方法,或者再C中按返回鍵的時候,在OnStop or OnPause or OnDestroy 中,觸發了System.exit 或者 Process.KillProcess,那麼程序將會重啓,但是重啓後回到的界面是A 而非B,應爲此時C還未添加到Task,或者已經從Task裏面移除了,所以會重啓回到除去棧頂的B 的下一個也就是A。當然如果C啓動完成已經添加到了Task裏面,在C中通過某個點擊事件獲取其他方式觸發了System.exit 或者 Process.KillProcess那麼會重啓回到B。

舉例2:
1:有一個App B ,有5個Activity : A,B,C,D,E 。其中A是啓動Activity,啓動順序爲 A->B->C->D-E。
2:假如C的activity:process = "com.test.process1",其他的Activity 使用默認的(名稱和ApplicationID 一樣),那麼當A 啓動了B 後B有啓動了C ,只要是在C中不管任何地方調用了System.exit 或者 Process.KillProcess都會結束掉“com.test.process1”這個進程,其他進程不受影響,所以C Activity 會關閉,但是A ,B 保持原樣。因爲C已經關閉了,根據Task 裏面的順序,所以顯示B 界面(效果和按返回鍵一樣,只是說按返回鍵不會結束掉進程);
3:接着第二種情況,假如不在C中調用,而是通過C啓動了D,因爲D 沒有指定process,所以D 和A,B 屬於同一個進程。那麼如果在D中執行了System.exit 或者 Process.KillProcess。那麼會結束掉D所在的進程,也就是默認名稱的進程,而C 在的進程不受影響,因此再執行System.exit 或者 Process.KillProcess後,會顯示C 界面,不會立刻重啓A,和B ,只有在C界面按返回的時候,這時候發現B 已經關閉了,所以系統會自動重啓B ,在B  中按返回,發現A也不存在了,所以會自動重啓A。針對此情況有一點需要補充一下,如果D 已經添加到Task 裏面後執行的結束方法,那麼回到C ,和上面所說的不矛盾(只是C不需要重啓因爲C在單獨的進程可以解釋得通),那麼如果是在D還未添加到Task 的時候,那麼此時Task 裏面只有A,B,C 三個。那麼爲什麼仍然回到C呢? 而不是B 呢?是因爲C 在單獨的進程,所以不受影響,而順序決定了C 在B 上面,所有隻有回到C而不是B。
4:如果A,B,屬於同一個進程,C,D,E 屬於另一個進程,如果此時Task裏面的狀態時A-B-C-D-E。 E 在棧頂,那麼在E 中執行了結束方法。會重啓E 所在的進程回到界面D。在D中按返回重啓C ,在C中按返回到B (不重啓,不再同一個進程)。
5:假如A,B,D 屬於同一進程同一個Task 。C 在另一個進程並且另一個Task.那麼當啓動完成D後,整個應用就有兩個Task 。最上一個(當前顯示的)Task { TaskRecord A,TaskRecord B,TaskReoced D},以及另一個Task{TaskRecord C}。那麼在D中執行結束方法,會重啓回到B界面,返回的順序是B->A->C.其中B,A 會重啓,C不會。

總結:總的來說就是當調用System.exit 或者 Process.KillProcess的時候,只會結束當前調用的進程(如果一個應用有多個進程,其他進程不會發生改變,其他進程裏面的activity 也不會重起),在根據結束之前整個應用的Tasks 狀態(數量和順序)來決定時候重啓,數量決定是否重啓,順序決定重啓後回到哪一個界面。
同樣,當發生RuntimeException 的時候和System.exit 或者 Process.KillProcess效果是一樣的。


轉自:http://www.ithao123.cn/content-2367268.html

發佈了474 篇原創文章 · 獲贊 383 · 訪問量 393萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章