Android组件管理框架:Android视图容器Activity

6125次阅读  |  发布于5年以前

本篇文章我们来分析Android的视图容器Activity,Android源码分析系列的文章终于写到了Activity,这个我们最常用,源码也最复杂的一个组件,之前在网上看到过很多关于Activity源码 分析的文章,这些文章写得都挺好,它们往往是从Activity启动流程这个角度出发,一个一个函数的去分析整个流程。但是这种做法会让文章通篇看去全是源码,而且会让读者产生一个疑问:这么 长的流程,我该如何掌握,掌握了之后有有什么意义吗?🤔

事实上,单纯去分析流程,确实看不出有什么实践意义,因此我们最好能带着日常开发遇到的问题去看源码,例如特殊场景下的生命周期是怎么变化的,为什么会出现ANR,不同启动模式下对Activity 入栈出栈有何影响等。我们带着问题去看看源码里是怎么写的,这样更有目的性,不至于迷失在茫茫多的源码中。

好了,闲话不多说,我们开始吧。😁

Activity作为Android最为常用的组件,它的复杂程度是不言而喻的。当我们点击一个应用的图标,应用的LancherActivity(MainActivity)开始启动,启动请求以一种IPC的方式传入AMS,AMS开始 处理启动请求,伴随着Intent与Flag的解析和Activity栈的进出,Activity的生命周期从onCreate()方法开始变化,最终将界面呈现在用户的面前。

Activity的复杂性主要体现在两个方面:

针对这些问题,我们来一一分析。

我们先来分析Activity启动流程,对Activity组件有个整体性的认识。

一 Activity的启动流程

Activity的启动流程图(放大可查看)如下所示:

整个流程涉及的主要角色有:

注:这里单独提一下ActivityStackSupervisior,这是高版本才有的类,它用来管理多个ActivityStack,早期的版本只有一个ActivityStack对应着手机屏幕,后来高版本支持多屏以后,就 有了多个ActivityStack,于是就引入了ActivityStackSupervisior用来管理多个ActivityStack。

整个流程主要涉及四个进程:

有了以上的理解,整个流程可以概括如下:

  1. 点击桌面应用图标,Launcher进程将启动Activity(MainActivity)的请求以Binder的方式发送给了AMS。
  2. AMS接收到启动请求后,交付ActivityStarter处理Intent和Flag等信息,然后再交给ActivityStackSupervisior/ActivityStack 处理Activity进栈相关流程。同时以Socket方式请求Zygote进程fork新进程。
  3. Zygote接收到新进程创建请求后fork出新进程。
  4. 在新进程里创建ActivityThread对象,新创建的进程就是应用的主线程,在主线程里开启Looper消息循环,开始处理创建Activity。
  5. ActivityThread利用ClassLoader去加载Activity、创建Activity实例,并回调Activity的onCreate()方法。这样便完成了Activity的启动。

👉 注:读者可以发现这上面有很多函数有Locked后缀,这代表这些函数需要进行多线程同步(synchronized)操作,它们会读写一些多线程共享的数据。

二 Activity的回退栈

要理解Activity回退栈,我们就要先理解Activity回退栈的功能结构,它的结构图如下所示:

主要角色有:

通过上面的图解分析,我想大家应该理解了Activity栈里的数据结构,接下来,我们再简单分析下这个数据类里的字段,字段比较多,大家有个印象就行,不必记住。

2.1 ActivityRecord

ActivityRecord基本上是一个纯数据类,里面包含了Activity的各种信息。

这个对象在ActivityStarter的startActivityLocked()方法里被构建,下面分析ActivityStarter的时候我们会说。

2.2 TaskRecord

TaskRecord的职责就是管理ActivityRecord,事实上,我们平时说的任务栈指的就是TaskRecord,所有ActivityRecord都必须要有宿主任务,如果不存在则新建一个。

我们前面说过TaskRecord是一个栈结构,它里面的函数当然也侧重栈的管理:增删改查。事实上,在内部TaskRecord是用ArrayList来实现的栈的操作。

基本上就是围绕ArrayList进行增删改查操作,再附加上一些状态变化,整个流程还是比较清晰的。

2.3 ActivityStack

ActivityStack的职责是管理多个任务栈TaskRecord。

我们都知道Activity有着很多生命周期状态,这些状态就是由ActivityStack来推动完成的,在ActivityStack里,Activity有九种状态:

这些状态的变化示意了Activity生命周期的走向。

我们也来简单看一下ActivityStack里的一些字段的含义:

Activity状态发生变化时,出来要调整ActivityRecord.state的状态,还要调整ActivityRecord在栈里的位置,事实上,ActivityStack也是一个栈式的结构,只不过它管理的是TaskRecord,和ActivityRecord 相关的操作也是先找到对应的TaskRecord,再由TaskRecord去完成具体的操作。

我们简单的看一下ActivityStack里面的方法。

注:这里提到了ActivityDisplay的概念,这里简单说一下,我们知道Android是支持多屏显示的,每个显示屏对应者一个ActivityDisplay,默认是手机屏幕,ActivityDisplay是ActivityStackSupervisior的一个内部类, ActivityStackSupervisor间接通过ActivityDisplay来维护多个ActivityStack的状态。 ActivityStack有一个属性是mStacks,当mStacks不为空时,表示ActivityStack已经绑定到了显示设备, 其实ActivityStack.mStacks 只是一个副本,真正的对象在ActivityDisplay中,ActivityDisplay的一些属性如下所示:

2.4 ActivityStackSupervisior

ActivityStackSupervisior用来管理ActivityStack。

ActivityStackSupervisior的一些常见属性如下所示:

ActivityStackSupervisior里有很多方法与ActivityStack里的方法类似,但是ActivityStackSupervisior是针对多个ActivityStack进行操作。例如:findTaskLocked(), findActivityLocked(), topRunningActivityLocked(), ensureActivitiesVisibleLocked()。

三 Activity的生命周期

Activity的生命周期也是个老生常谈的问题,今天我们从源码的角度去分析Activity的生命周期是如何驱动的,以及它是如何变化的。

这里贴一张android-lifecycle项目关于Activity与Fragment生命周期图

读者可以从上图看出,Activity有很多种状态,状态之间的变化也比较复杂,在众多状态中,只有三种是常驻状态:

其他的状态都是中间状态。

我们再来看看生命周期变化时的整个调度流程,生命周期调度流程图如下所示:

所以你可以看到,整个流程是这样的:

  1. 比方说我们点击跳转一个新Activity,这个时候Activity会入栈,同时它的生命周期也会从onCreate()到onResume()开始变换,这个过程是在ActivityStack里完成的,ActivityStack 是运行在Server进程里的,这个时候Server进程就通过ApplicationThread的代理对象ApplicationThreadProxy向运行在app进程ApplicationThread发起操作请求。
  2. ApplicationThread接收到操作请求后,因为它是运行在app进程里的其他线程里,所以ApplicationThread需要通过Handler向主线程ActivityThread发送操作消息。
  3. 主线程接收到ApplicationThread发出的消息后,调用主线程ActivityThread执行响应的操作,并回调Activity相应的周期方法。

👉 注:这里提到了主线程ActivityThread,更准确来说ActivityThread不是线程,因为它没有继承Thread类或者实现Runnable接口,它是运行在应用主线程里的对象,那么应用的主线程 到底是什么呢?从本质上来讲启动启动时创建的进程就是主线程,线程和进程处理是否共享资源外,没有其他的区别,对于Linux来说,它们都只是一个struct结构体。

上述这个流程的函数调用链如下所示:

ActivityThread.handleLaunchActivity
    ActivityThread.handleConfigurationChanged
        ActivityThread.performConfigurationChanged
            ComponentCallbacks2.onConfigurationChanged

    ActivityThread.performLaunchActivity
        LoadedApk.makeApplication
            Instrumentation.callApplicationOnCreate
                Application.onCreate

        Instrumentation.callActivityOnCreate
            Activity.performCreate
                Activity.onCreate

        Instrumentation.callActivityonRestoreInstanceState
            Activity.performRestoreInstanceState
                Activity.onRestoreInstanceState

    ActivityThread.handleResumeActivity
        ActivityThread.performResumeActivity
            Activity.performResume
                Activity.performRestart
                    Instrumentation.callActivityOnRestart
                        Activity.onRestart

                    Activity.performStart
                        Instrumentation.callActivityOnStart
                            Activity.onStart

                Instrumentation.callActivityOnResume
                    Activity.onResume

其他的生命周期在变化时调用流程和上面是一样的,读者可以自己举一反三。

启动新的Activity发出的消息是LAUNCH_ACTIVITY,这些消息定义在ActivityThread的内部类H(Handler)里,一共有54个,大部分都是我们熟悉的操作。

public static final int LAUNCH_ACTIVITY         = 100;
public static final int PAUSE_ACTIVITY          = 101;
public static final int PAUSE_ACTIVITY_FINISHING= 102;
public static final int STOP_ACTIVITY_SHOW      = 103;
public static final int STOP_ACTIVITY_HIDE      = 104;
public static final int SHOW_WINDOW             = 105;
public static final int HIDE_WINDOW             = 106;
public static final int RESUME_ACTIVITY         = 107;
public static final int SEND_RESULT             = 108;
public static final int DESTROY_ACTIVITY        = 109;
public static final int BIND_APPLICATION        = 110;
public static final int EXIT_APPLICATION        = 111;
public static final int NEW_INTENT              = 112;
public static final int RECEIVER                = 113;
public static final int CREATE_SERVICE          = 114;
public static final int SERVICE_ARGS            = 115;
public static final int STOP_SERVICE            = 116;

public static final int CONFIGURATION_CHANGED   = 118;
public static final int CLEAN_UP_CONTEXT        = 119;
public static final int GC_WHEN_IDLE            = 120;
public static final int BIND_SERVICE            = 121;
public static final int UNBIND_SERVICE          = 122;
public static final int DUMP_SERVICE            = 123;
public static final int LOW_MEMORY              = 124;
public static final int ACTIVITY_CONFIGURATION_CHANGED = 125;
public static final int RELAUNCH_ACTIVITY       = 126;
public static final int PROFILER_CONTROL        = 127;
public static final int CREATE_BACKUP_AGENT     = 128;
public static final int DESTROY_BACKUP_AGENT    = 129;
public static final int SUICIDE                 = 130;
public static final int REMOVE_PROVIDER         = 131;
public static final int ENABLE_JIT              = 132;
public static final int DISPATCH_PACKAGE_BROADCAST = 133;
public static final int SCHEDULE_CRASH          = 134;
public static final int DUMP_HEAP               = 135;
public static final int DUMP_ACTIVITY           = 136;
public static final int SLEEPING                = 137;
public static final int SET_CORE_SETTINGS       = 138;
public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
public static final int TRIM_MEMORY             = 140;
public static final int DUMP_PROVIDER           = 141;
public static final int UNSTABLE_PROVIDER_DIED  = 142;
public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
public static final int INSTALL_PROVIDER        = 145;
public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
public static final int CANCEL_VISIBLE_BEHIND = 147;
public static final int BACKGROUND_VISIBLE_BEHIND_CHANGED = 148;
public static final int ENTER_ANIMATION_COMPLETE = 149;
public static final int START_BINDER_TRACKING = 150;
public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
public static final int MULTI_WINDOW_MODE_CHANGED = 152;
public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;

我们前面说到Activity的生命周期是由ActivityStack来驱动的,应用的Activity在切换时,ActivityStack会对相应的任务战TaskRecord进行调整,以前的Activity要出栈 销毁或者移动到后台,要显示的Activity添加到栈顶。伴随着对任务栈的操作,Activity的生命周期也在不断的变化。

在ActivityStack里与Activity生命周期变化有关的函数主要有以下几个:

四 Activity的启动模式

启动模式会影响Activity的启动行为,默认情况下,启动一个Activity就是创建一个实例,然后进入回退栈,但是我们可以通过启动模式来改变这种行为,实现不同的交互效果。

那么有哪些设置会影响这种行为呢?🤔

首先是标签里的参数:

注:更多和标签相关的参数可以参见activity-element

然后是Intent里的标志位:

什么情况下需要设置FLAG_ACTIVITY_NEW_TASK标志位呢?🤔

一般说来,主要有以下四种情况:

启动模式一共有四种:

我们再来总结一下这些启动模式的区别:

我们前面说过,ActivityRecord里有个ActivityInfo成员变量用来描述Activity的相关信息,ActivityInfo是在解析AndroidManifest.xml里的标签获取的。 它里面的launchMode对应上面启动模式。

public static final int LAUNCH_MULTIPLE = 0;
public static final int LAUNCH_SINGLE_TOP = 1;
public static final int LAUNCH_SINGLE_TASK = 2;
public static final int LAUNCH_SINGLE_INSTANCE = 3;

五 Activity的通信方式

Activity之间也经常需要传递数据,这个一般通过以下方式来完成。

原始Activity

startActivityForResult(intent, requestCode, resultCode);

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
}

目标Activity

setResult(resultCode, intent);

我们来看下setResult()方法的实现。

public final void setResult(int resultCode, Intent data) {
    synchronized (this) {
        mResultCode = resultCode;
        mResultData = data;
    }
}

就是个简单的赋值操作,这说明会有方法来去这个变量的值,什么时候来取?🤔根据平时的开发经验,Activity finsh()或者onBackPress()来取,将这两个值通过 onActivityResult(int requestCode, int resultCode, Intent data)返回给原始Activity。

我们来梳理一下整个流程。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8