System.exit和Process.killProcess

本文转载自:https://blog.csdn.net/gaojinshan/article/details/52870739

首先,在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

猜你喜欢

转载自blog.csdn.net/okg0111/article/details/80524537