本篇文章我们来分析Android的视图容器Activity,Android源码分析系列的文章终于写到了Activity,这个我们最常用,源码也最复杂的一个组件,之前在网上看到过很多关于Activity源码 分析的文章,这些文章写得都挺好,它们往往是从Activity启动流程这个角度出发,一个一个函数的去分析整个流程。但是这种做法会让文章通篇看去全是源码,而且会让读者产生一个疑问:这么 长的流程,我该如何掌握,掌握了之后有有什么意义吗?🤔
事实上,单纯去分析流程,确实看不出有什么实践意义,因此我们最好能带着日常开发遇到的问题去看源码,例如特殊场景下的生命周期是怎么变化的,为什么会出现ANR,不同启动模式下对Activity 入栈出栈有何影响等。我们带着问题去看看源码里是怎么写的,这样更有目的性,不至于迷失在茫茫多的源码中。
好了,闲话不多说,我们开始吧。😁
Activity作为Android最为常用的组件,它的复杂程度是不言而喻的。当我们点击一个应用的图标,应用的LancherActivity(MainActivity)开始启动,启动请求以一种IPC的方式传入AMS,AMS开始 处理启动请求,伴随着Intent与Flag的解析和Activity栈的进出,Activity的生命周期从onCreate()方法开始变化,最终将界面呈现在用户的面前。
Activity的复杂性主要体现在两个方面:
针对这些问题,我们来一一分析。
我们先来分析Activity启动流程,对Activity组件有个整体性的认识。
Activity的启动流程图(放大可查看)如下所示:
整个流程涉及的主要角色有:
注:这里单独提一下ActivityStackSupervisior,这是高版本才有的类,它用来管理多个ActivityStack,早期的版本只有一个ActivityStack对应着手机屏幕,后来高版本支持多屏以后,就 有了多个ActivityStack,于是就引入了ActivityStackSupervisior用来管理多个ActivityStack。
整个流程主要涉及四个进程:
有了以上的理解,整个流程可以概括如下:
👉 注:读者可以发现这上面有很多函数有Locked后缀,这代表这些函数需要进行多线程同步(synchronized)操作,它们会读写一些多线程共享的数据。
要理解Activity回退栈,我们就要先理解Activity回退栈的功能结构,它的结构图如下所示:
主要角色有:
通过上面的图解分析,我想大家应该理解了Activity栈里的数据结构,接下来,我们再简单分析下这个数据类里的字段,字段比较多,大家有个印象就行,不必记住。
ActivityRecord基本上是一个纯数据类,里面包含了Activity的各种信息。
这个对象在ActivityStarter的startActivityLocked()方法里被构建,下面分析ActivityStarter的时候我们会说。
TaskRecord的职责就是管理ActivityRecord,事实上,我们平时说的任务栈指的就是TaskRecord,所有ActivityRecord都必须要有宿主任务,如果不存在则新建一个。
我们前面说过TaskRecord是一个栈结构,它里面的函数当然也侧重栈的管理:增删改查。事实上,在内部TaskRecord是用ArrayList来实现的栈的操作。
基本上就是围绕ArrayList进行增删改查操作,再附加上一些状态变化,整个流程还是比较清晰的。
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的一些属性如下所示:
ActivityStackSupervisior用来管理ActivityStack。
ActivityStackSupervisior的一些常见属性如下所示:
ActivityStackSupervisior里有很多方法与ActivityStack里的方法类似,但是ActivityStackSupervisior是针对多个ActivityStack进行操作。例如:findTaskLocked(), findActivityLocked(), topRunningActivityLocked(), ensureActivitiesVisibleLocked()。
Activity的生命周期也是个老生常谈的问题,今天我们从源码的角度去分析Activity的生命周期是如何驱动的,以及它是如何变化的。
这里贴一张android-lifecycle项目关于Activity与Fragment生命周期图
读者可以从上图看出,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-element。
然后是Intent里的标志位:
什么情况下需要设置FLAG_ACTIVITY_NEW_TASK标志位呢?🤔
一般说来,主要有以下四种情况:
启动模式一共有四种:
我们再来总结一下这些启动模式的区别:
我们前面说过,ActivityRecord里有个ActivityInfo成员变量用来描述Activity的相关信息,ActivityInfo是在解析AndroidManifest.xml里的
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
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。
我们来梳理一下整个流程。
扫一扫
在手机上阅读