大家都知道,Android可以同时运行多个应用并且支持互相之间的切换,这是因为Android是基于Linux的多用户、多任务的操作系统,Android应用的启动与执行同样也是基于Linux进程的。
Linux进程
Linux为每个用户分配一个唯一的UserId,并通过沙盒机制来隔离每个用户,每个用户通过权限控制只能访问属于自己的资源(root用户除外)。在Android中,每个App相当于一个用户,因此这些应用只能访问自己的数据,而不能访问其他App的资源。通常情况下,当启动一个App时,Android系统会为该应用启动一个进程和一个独享的虚拟机,如下图(图片来自Efficient Android Threading)所示:
如上所述,一般情况下,每个App运行在一个独立的进程中,当然如果有需要,也可以让一个App运行在多个进程中(如App中的Service可以运行在另一个进程中),或者让多个App运行在同一个进程中(如插件化加载机制,可以通过共享UserId实现)。
应用程序的生命周期
通过android.app.Application
这个类可知,其启动于onCreate()
方法,终止于onTerminate()
方法,但是onTerminate()
的API中明确说明:此回调只存在于模拟环境,在真正的Android设备上是不会被执行的。事实上,一个应用程序的终止是由于系统杀死了其所在的进程,具体原因及过程下面会详细分析。
应用程序的启动
一个应用初次启动时一般会遵循如下流程:
- 启动一个Linux进程
- 创建runtime
- 创建Application实例
- 创建第一个启动的组件,如启动页Activity
这样一个App就运行起来了,需要注意的是,前两个步骤是需要系统开销及时间的,而App又可能会被频繁启动,因此可能导致不好的用户体验,因此Zygote就出现了。Zygote也是一个进程,它是在系统启动时就创建好了,并且它已经预加载且共享核心类库,这样当启动一个App时,其所需的进程就fork自Zygote进程,这样就加快了应用的启动速度,提升了用户体验。事实上,所有的App进程都是fork自Zygote进程,也可以说Zygote进程是所有应用的父进程,这一点通过打印应用程序的PPID(Parent process identifier)可以验证。
应用程序的终止
说完了应用的启动,再来看应用是如何终止的。前文讲onTerminate()
回调在生产环境中是不会被调用的,这是因为用户随时都可能启动应用,如果当所有组件都destory后,每当退出应用时就销毁掉其所有资源,杀掉其进程,那么再次启动应用时就需要重新创建进程,很可能刚退出就又启动,或者过了一小会儿就重新启动,这样的开销是不容忽视的。因此系统巧妙地设计为当应用退出时并非立即销毁掉其资源,而是当系统资源不足时才按优先级杀掉部分进程。于是可以得到这样的结论:应用程序不会主动终止自己,即使所有的组件都已经销毁了。这也是前文“初次启动”几个字加粗说明的原因,即如果进程还未被系统销毁,再次启动时则不必重新创建进程。
最后再来看各种进程的优先级:
- 前台进程——如正在前台运行的应用、绑定前台Activity的远程Service、正在运行的BroadcastReceiver
- 可见进程——如Activity被部分遮挡的应用
- 服务——如未绑定任何可见组件,但在后台运行的Service
- 后台进程——例如应用被切到后台,所有的Activity已经不可见
- 空进程——已经没有任何存活组件的应用进程,它们的存在仅为了下次更好的启动,当系统资源不足时,这类进程是最先被系统杀死的。