首页 > 技术文章 > Activity组件的启动过程

huolongluo 2021-12-14 10:29 原文

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组件的过程如下:

  1. Launcher组件向ActivityManagerService发送一个启动MainActivity组件的进程间通信请求。
  2. ActivityManagerService首先将要启动的MainActivity组件的信息保存下来,然后再向Launcher组件发送一个进入中止状态的进程间通信请求。
  3. Launcher组件进入到中止状态之后,就会向ActivityManagerService发送一个已进入中止状态的进程间通信请求,以便ActivityManagerService可以继续执行启动MainActivity组件的操作。
  4. ActivityManagerService发现用来运行MainActivity组件的应用程序进程不存在,因此,就会先启动一个新的应用程序进程。
  5. 新的应用程序进程启动完成之后,就会向ActivityManagerService发送一个启动完成的进程间通信请求,以便ActivityManagerService可以继续执行启动MainActivity组件的操作。
  6. 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();
 7             Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
 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组件启动起来。

推荐阅读