Activity是Android应用程序的四大组件之一,负责管理Android应用程序界面。一个应用程序中的多个Activity可能运行在同一个进程中,也可能运行在不同的进程中。不同进程中的Activity组件通过Binder进程间通信机制来传输数据。
从App程序的角度出发,Activity组件分为两类,一个是根Activity,一个是子Activity。根Activity以快捷图标的形式显示在应用程序的启动器中,它的启动过程就表示了一个App应用程序的启动过程。Activity的启动又分为“显示启动”、“隐式启动”。它们的启动过程都是类似的。唯一的区别在于系统是根据类名启动,还是根据组件名称来找到并启动。从软件工程的角度,隐式启动Activity的方式,可以减少Android应用程序组件间的依赖关系。
当MainActivity组件被应用程序启动器中的Launcher组件启动起来之后,通过“adb shell dumpsys activity”命令可以查看到程序Activity相关启动信息:
可以看到,所有的Activity都会进入到一个堆栈当中,后启动的Activity组件会位于前面启动的Activity组件上面。MainActivity组件是由Lanucher组件来启动的,而Lanucher组件又是通过Activity管理服务ActivityManagerService来启动MainActivity的(ActivityManagerService是一个系统关键服务,它运行在系统进程System中,负责启动和调度应用程序组件)。又因为MainActivity组件、Lanucher组件和ActivityManagerService是分别运行在不同的进程中,因此一个MainActivity组件的启动过程,就涉及到了三个进程。它们之间通过Binder进程间的通信机制来完成MainActivity的启动过程。
Launcher组件启动一个MainActivity组件的过程如下:
- Launcher组件向ActivityManagerService发送一个启动MainActivity组件的进程间通信请求。
- ActivityManagerService首先将要启动的MainActivity组件的信息保存下来,然后再向Launcher组件发送一个进入中止状态的进程间通信请求。
- Launcher组件进入到中止状态之后,就会向ActivityManagerService发送一个已进入中止状态的进程间通信请求,以便ActivityManagerService可以继续执行启动MainActivity组件的操作。
- ActivityManagerService发现用来运行MainActivity组件的应用程序进程不存在,因此,就会先启动一个新的应用程序进程。
- 新的应用程序进程启动完成之后,就会向ActivityManagerService发送一个启动完成的进程间通信请求,以便ActivityManagerService可以继续执行启动MainActivity组件的操作。
- ActivityManagerService将第2步保存下来的MainActivity组件的信息发送给第4步创建的应用程序进程,以便它可以将MainActivity组件启动起来。
(MainActivity的启动过程)从步骤1,到步骤5,如图所示:
在系统源码package/apps/Launcher2/src/com/android/launcher2/Launcher.java类中有一个startActivitySafely方法:
1 boolean startActivitySafely(View v, Intent intent, Object tag) {
2 boolean success = false;
3 try {
4 success = startActivity(v, intent, tag);
5 } catch (ActivityNotFoundException e) {
6 Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
8 }
9 return success;
10 }
当我们在应用程序启动器Launcher的界面上点击一个应用程序的快捷图标时,Launcher组件的成员函数startActivitySafely就会被调用,来启动这个应用程序的根Activity,其中,要启动的根Activity的信息就包含在参数Intent当中。
例如,当应用程序Activity的MainActivity组件被Launcher组件启动时,参数Intent所包含的Activity组件信息就如下所示:
1 action = "android.intent.action.Main"
2 category = "android.intent.category.LAUNCHER"
3 cmp = "com.szcm.sample.huolongluo.ui.activity.main.MainActivity"
第1行和第2行分别表示要启动的Activity组件的Action名称和Category名称。而第3行表示这个Activity组件是由“com.szcm.sample.huolongluo.ui.activity.main.MainActivity”类来实现的。
这时候会思考,Launcher组件是如何获得这些信息的?系统在启动时,会启动一个Package管理服务PackageManagerService(简称PMS),并且通过它来安装系统中的应用程序。PMS在安装一个应用程序的过程中,会对它的清单文件AndroidManifest.xml进行解析,从而得到它里面的组件信息。系统启动完成之后,就会将Launcher组件启动起来。Launcher组件在启动过程中,会向PMS查询所有所有Action名称等于“Intent.ACTION_MAIN”,并且Category名称等于“Intent.CATEGORY_LAUNCHER”的Activity组件,最后为每一个Activity组件创建一个快捷图标,并且将它们的信息与各自的快捷图标关联起来,以便用户在点击它们的时候,可以将对应的根Activity组件启动起来。