美文网首页
Activity 组件的启动过程

Activity 组件的启动过程

作者: JunL_Dev | 来源:发表于2020-01-08 17:32 被阅读0次
    Start

    前言

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

    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 组件启动起来。

    3. 子 Activity 组件再进程内的启动过程

    以应用程序 Activity 的 SubActivityInProcess 组件的启动过程来说明。过程如下:

    1. MainActivity 组件向 ActivityManagerService 发送一个启动 SubActivityInProcess 组件的进程间通信请求。

    2. ActivityManagerService 首先将要启动的 SubActivityInProcess 组件的信息保存下来,然后再向 MainActivity 组件发送一个 进入中止状体的进程间通信请求。

    3. MainActivity 组件进入到中止状态之后,就会向 ActivityManagerService 发送一个已经进入中止状态的进程间通信请求,以便 ActivityManagerService 可以继续执行启动 SubActivityInProcess 组件的操作。

    4. ActivityManagerService 发现用来运行 SubActivityInProcess 组件的应用程序进程已经存在,因此它就会将第2步保存下来的 SubActivityInProcess 组件信息发送给该程序进程,以便它可以将 SubActivityInProcess 组件启动起来。

    4. 子 Activity 组件在新进程中的启动过程

    以应用程序 Activity 的 SubActivityInNewProcess 组件的启动过程来说明。过程如下:

    1. MainActivity 组件向 ActivityManagerService 发送一个启动 SubActivityInNewProcess 组件的进程间通信请求。

    2. ActivityManagerService首先将要启动的 SubActivityInNewProcess 组件的信息保存下来,然后再向 MainActivity 组件发送一个进入中止状态的进程间通信请求。

    3. MainActivity 组件进入到中止状态之后,就会向 ActivityManagerService 发送一个已进入中止状态的进程间通信请求,以便 ActivityManagerService 可以继续执行启动 SubActivityInNewProcess 组件的操作。

    4. ActivityManagerService 发现用来运行 SubActivityInNewProcess 组件的应用程序进程不存在,因此它就会先启动一个新的应用程序进程。

    5. 新的应用程序启动完成之后,就会向 ActivityManagerService 发送一个启动完成的进程间通信请求,以便 ActivityManagerService 可以继续执行启动 SubActivityInNewProcess 组件的操作。

    6. 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系统源代码情景分析》

    相关文章

      网友评论

          本文标题:Activity 组件的启动过程

          本文链接:https://www.haomeiwen.com/subject/kycfactx.html