前言
Activity 组件的启动方式分为显示和隐式两种。对于显示 Activity 组件来说,我们必须事先知道用来实现他们类的名称;而对于隐式启动的 Activity 来说,我们只需要知道他们的组件名称即可,而不需要知道他们是由哪个类来实现的,唯一的区别在于系统是根据类名还是组件名来找到他们。但是,从组件的角度来看,隐式启动 Activity 组件可以减少 Android 应用程序组件间的依赖,因此,我们主要来分析一下隐式启动过程。
1. 准备
准备三个 Activity 分别是 MainActivity、SubActivityInProcess 和 SubActivityInNewProcess。其中,MainActivity 是 根 Activity,SubActivityInProcess 和 SubActivityInNewProcess 是子 Activity。MainActivity 和 SubActivityInProcess 在同一个进程,而 SubActivityInNewProcess 运行在一个独立的进程中。
MainActivity.class
public class MainActivity extends AppCompatActivity {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_start_sub_process).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent("com.android.junl_note.Android.SubActivityInProcess"));
}
});
findViewById(R.id.btn_start_sub_new_process).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent("com.android.junl_note.Android.SubActivityInNewProcess"));
}
});
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/btn_start_sub_process"
android:text="btn_start_sub_process"
android:textColor="#fff"
android:background="#3f51b5"
android:layout_width="match_parent"
android:layout_height="50dp"/>
<Button
android:id="@+id/btn_start_sub_new_process"
android:text="btn_start_sub_new_process"
android:textColor="#fff"
android:layout_marginTop="30dp"
android:background="#3f51b5"
android:layout_width="match_parent"
android:layout_height="50dp"/>
</LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.junl_note">
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:process=":main">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Android.SubActivityInProcess"
android:process=":main">
<intent-filter>
<action android:name="com.android.junl_note.Android.SubActivityInProcess" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".Android.SubActivityInNewProcess"
android:process=":work">
<intent-filter>
<action android:name="com.android.junl_note.Android.SubActivityInNewProcess" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
SubActivityInProcess 和 SubActivityInNewProcess 只是简单的 Activity,代码就不贴出来了,准备工作完成。
2. 根 Activity 组件的启动过程
以 MainActicity 组件的启动过程为例,来说明 Android 应用程序的根 Activity 组件的启动过程,即 Android 应用程序的启动过程。
当 MainActivity 组件被应用程序启动器中的 Launcher 组件启动起来之后,我们就可以通过 adb shell dumpsys activity
命令查看到它的信息:
···
TaskRecord{1fb3b8c #12423 A=com.android.junl_note U=0 StackId=1 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.android.junl_note/.MainActivity }
Hist #0: ActivityRecord{a5328b1 u0 com.android.junl_note/.MainActivity t12423}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.android.junl_note/.MainActivity }
ProcessRecord{d9c97c0 9252:com.android.junl_note:main/u0a1513}
Running activities (most recent first):
TaskRecord{1fb3b8c #12423 A=com.android.junl_note U=0 StackId=1 sz=1}
Run #0: ActivityRecord{a5328b1 u0 com.android.junl_note/.MainActivity t12423}
mResumedActivity: ActivityRecord{a5328b1 u0 com.android.junl_note/.MainActivity t12423}
···
MainActivity 组件是由 Launcher 组件来启动的,而 Launcher 组件又是通过 Activity 管理服务 ActivityManagerService 来启动的。由于 MainActivity 组件、Launcher 组件和 ActivityManagerService 是分别运行在不同进程中的,因此,MainActivity 组件的启动过程涉及到了三个进程。这三个进程是通过 Binder 进程间通信机制来完成 MainActivity 组件的启动过程的。
ActivityManagerService是一个系统关键服务,他运行在系统进程 System 中,负责启动和调度应用程序组件,它的启动过程后面的文章会说到。
Launcher 组件启动 MainActivity 组件的过程如下所示:
-
Launcher 组件向 ActivityManagerService 发送一个启动 MainActivity 组件的进程间通信请求。
-
ActivityManagerService 首先将要启动的 MainActivity 组件的信息保存下来,然后再向 Launcher 组件发送一个进入中止状态的进程间通信请求。
-
Launcher 组件进入到中止状态之后,就会向 ActivityManagerService 发送一个已经进入中止状态的进程间通信请求,以便 ActivityManagerService 可以继续执行启动 MainActivity 组件的操作。
-
ActivityManagerService 发现用来执行 MainActivity 组件的应用程序进程不存在,因此,它就会先启动一个新的应用程序进程。
-
新的应用程序进程启动完成之后,就会向 ActivityManagerService 发送一个启动完成的进程间通信请求,以便 ActivityManagerService 可以继续执行启动 MainActivity 组件的操作。
-
ActivityManagerService 将第2步保存下来的 MainActivity 组件信息发送给第4步创建的应用程序进程,以便它可以将 MainActivity 组件启动起来。
3. 子 Activity 组件再进程内的启动过程
以应用程序 Activity 的 SubActivityInProcess 组件的启动过程来说明。过程如下:
-
MainActivity 组件向 ActivityManagerService 发送一个启动 SubActivityInProcess 组件的进程间通信请求。
-
ActivityManagerService 首先将要启动的 SubActivityInProcess 组件的信息保存下来,然后再向 MainActivity 组件发送一个 进入中止状体的进程间通信请求。
-
MainActivity 组件进入到中止状态之后,就会向 ActivityManagerService 发送一个已经进入中止状态的进程间通信请求,以便 ActivityManagerService 可以继续执行启动 SubActivityInProcess 组件的操作。
-
ActivityManagerService 发现用来运行 SubActivityInProcess 组件的应用程序进程已经存在,因此它就会将第2步保存下来的 SubActivityInProcess 组件信息发送给该程序进程,以便它可以将 SubActivityInProcess 组件启动起来。
4. 子 Activity 组件在新进程中的启动过程
以应用程序 Activity 的 SubActivityInNewProcess 组件的启动过程来说明。过程如下:
-
MainActivity 组件向 ActivityManagerService 发送一个启动 SubActivityInNewProcess 组件的进程间通信请求。
-
ActivityManagerService首先将要启动的 SubActivityInNewProcess 组件的信息保存下来,然后再向 MainActivity 组件发送一个进入中止状态的进程间通信请求。
-
MainActivity 组件进入到中止状态之后,就会向 ActivityManagerService 发送一个已进入中止状态的进程间通信请求,以便 ActivityManagerService 可以继续执行启动 SubActivityInNewProcess 组件的操作。
-
ActivityManagerService 发现用来运行 SubActivityInNewProcess 组件的应用程序进程不存在,因此它就会先启动一个新的应用程序进程。
-
新的应用程序启动完成之后,就会向 ActivityManagerService 发送一个启动完成的进程间通信请求,以便 ActivityManagerService 可以继续执行启动 SubActivityInNewProcess 组件的操作。
-
ActivityManagerService 将第2步保存下来的 SubActivityInNewProcess 组件信息发送给第4步创建的应用程序进程,以便它可以将 SubActivityInNewProcess 组件启动起来。
5. 总结
从 MainActivity 组件、SubActivityInProcess 组件和 SubActivityInNewProcess 组件的启动过程可以看出,一个 Activity 组件是在一个已经存在的应用程序中启动,还是在一个新创建的应用程序进程中启动,是由两个因素决定的。
-
第一个因素是这个 Activity 组件的用户 ID,即 PackageManagerService 分配给它所属的 Android 应用程序的用户 ID;
-
第二个因素是这个 Activity 组件的 android:process 属性。
从这一点可以看出,一个 Android 应用程序是可以对应于多个应用程序进程的。
还可以看出,每一个 Activity 都是运行在一个任务(Task)中的。任务是一个比进程更高级和抽象的概念,用来将一系列相关的 Activity 组件整合在一起,共同完成一个业务功能。由于任务可以将运行在不同进程中的 Activity 组件整合在一起,因此,这就使得 Activity 组件的重用性非常强。
例如,假设系统中有一个 Email 应用程序,它里面包含了一个用来发送 E-mail 的 Activity 组件 EmailSender 。它开发其他原因程序时,如果一个 Activity 组件 SomeActivity,它需要一个 E-mail 发送功能,那么它就完全可以将 Email 原因程序中的 EmailSender 组件启动起来,并且运行在同一个任务中,等到 E-mail 发送完成之后再返回到 SomeActivity 组件中。在整个 E-mail 的发送过程中,用户完全感觉不到 SomeActivity 组件和 EmailSender 组件是运行在两个不同的应该程序进程中的。这个,EmailSender 组件的重用性就非常强。
申明:开始的图片来源网络,侵删
参考文献:《Android系统源代码情景分析》
网友评论