概述
Activity是我们开发中使用的最多、最频繁的程序组件。通过在AndroidManifest.xml中构建一个Activity标签,我们就可以通过startActivity方法将其以一个窗口页面的形式呈现在屏幕上,用户可以通过这个窗口进行诸如发短信、聊天、打电话等操作。
基于繁杂的功能需求与交互需要,一个应用程序通常由多个Activity组成,它们彼此之间来回切换呈现在屏幕上与用户进行交互,依据Activity是否处于前台等状态的不同,这就产生了Activity生命周期的概念。
掀开Activity的面纱
Activity的生命周期
下图很直观的展示了Activity的生命周期。

根据上图,Activity一般分为以下几种状态:
- 初始化状态。指的是Activity创建阶段的状态,当我们调用startActivity启动另外一个Activity时,如果这个Activity当前还没有,则由Instrumentation创建并调用其onCreate与onStart生命周期方法。
- 可见状态。指的是Activity可被用户看见被不能与用户交互,不能响应手势、点击事件。例如,正在交互中的Activity被系统错误弹窗顶掉,处于部分可见时,其会通过onPause方法告知Activity当前处于可见状态。
- 前台状态。意味着当前Activity可以与用户交互,在onResume方法调用之后就处于前台状态,当前Activity不仅离用户最近,从task来看也必处于栈顶。
- 后台状态。意味着当前Activity因被另一Activity切换掉而处于完全不可见的状态,处于后台状态的Activity可能被用户重新切到前台,也有可能被销毁。
- 销毁状态。指的是用户已经不需要再使用这个Activity页面时,点击back按键或因finish方法而导致Activity被移除出栈,因而触发的onDestroy生命周期方法(可能不是立即触发)。
为了有效的管理Activity的生命周期,Activity特别声明了以下几个成员变量,可以预见的是它们各自标识了当前是否处于对应的状态,例如:mResumed=true则表示当前Activity处于前台。
// frameworks/base/core/java/android/app/Activity.java
/*package*/ boolean mResumed;
private boolean mStopped;
boolean mFinished;
private boolean mDestroyed;
需要说明的是,Activity执行生命周期方法是通过调用performXXXX()完成的。很容易想到,在performPause()和performStop中mResumed被置成false,performResume()则把mResumed置为true。而mStopped则在performStop中被置成true,且通过判断防止状态被多次分发调用。
mFinished则用于标识当前Activity是否有调用finish()或finishAffinity()方法,因为一旦finish,则当前Activity就会从他所在的任务栈中移除,处于可被系统回收的状态。而mDestroyed则调用performDestroy()时被置为true,这时关于此Activity的使用的系统资源已经被清理掉。
相应的,以下方法有助于我们判断当前的状态:
- isResumed()。当前Activity是否处于前台,即用户可交互状态。
- isFinishing()。当前Activity生命周期是否已经结束。
- isDestroyed()。当前Activity是否已经被销毁。
生命周期方法在应用端的调用过程大致如下图所示。当然,此处省略了H类把binder线程消息转到主线程处理的过程。

上图中有所有的生命周期都经过Instrumentation调用完成,这也正是Instrumentation可以成为测试框架的重要原因,网络上也不乏网友通过反射hook它来观察或改变Activity运行状态的例子。
Activity使用了mCalled变量来保证我们重写其生命周期方法时必须使用super调用父类的生命周期方法,这个mCalled方法一般在performXXXX()中被置为false,则在onXXXX()中被置为true,如果子类重写时没有调用Activity的onXXXX(),则会因其后mCalled变量检查为false而报错。在这些onXXXX()方法中,除了进行基本的操作外,还对Activity的运行状态进行了分发。例如我们的onResume中:
// frameworks/base/core/java/android/app/Activity.java
protected void onResume() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
getApplication().dispatchActivityResumed(this);
mActivityTransitionState.onResume();
mCalled = true;
}
Activity的的运行状态被Application实例dispatch出去,这些分发出去的运行状态我们可以在Appliacation中通过方法registerActivityLifecycleCallbacks()完成监听。这其实是很有用的,特别是应用有埋点需求或需要使用一些统计框架来统计页面停留时。
继承关系及关键成员
用户虽然是通过Activity进行屏幕交互,且Activity也拥有完整的生命周期来标识这一交互过程,但其拥有的能力却并非源于自己。
先来简单说下Activity的继承关系,如下:

从继承关系上来看,Activity本质上是一个Context,其拥有当前页面的上下文环境,像Context的能力诸如使用系统服务、资源访问等功能Activity自然也就具备了。
Activity内部的关键成员有:
- mInstrumentation。用于系统组件的初始化及监控系统与应用的交互,可以通过hook它对系统组件部分功能进行重新定义,例如我们的插件化技术。同时,测试框架大都通过继承此类并重写其onCreate()、onStart()、callActivityOnXXXX()等方法来测试Activity运行情况。
- mToken。属于Ibinder类型,很明显的是属于跨进程调用的一部分。其本质上是ActivityRecord$Token类型,继承自IApplicationToken(的子类),其内部包含了ActivityRecord(这是AMS端用来记录每个Activity的类)的弱引用。在当前Activity与AMS进行通信的过程中,mToken唯一标识了这个Activity。
- mApplication。属于Application类型,通过调用Process.start()方法启动一个ActivityThread后最终通过handleBindApplication()创建(这里需要说明的是,Instrumentation也是在handleBindApplication()中创建的),其属于进程唯一实例。Activity可以通过getApplication()获取这个实例进而调用Application的方法。
- mMainThread、mUiThread。mMainThread标识了当前进程主线程,而mUiThread则标识当前UI线程,它们在attach()方法中被赋值。通常情况下,两者都是ActivityThread。因为Activity的attach()方法通常都是在ActivityThread线程中调用,具体来说,在ActivityThread中,H类(Handler的子类)负责把处于binder线程的AMS消息转到H所在的ActtivityThread线程中执行,而我们Activity的attach()方法就是在在转过来的handleLaunchActivity()方法中被调用。然而,mMainThread与mUiThread并非总是标识了ActivityThread,在使用了Instrumentation的测试场景下,Instrumentation会创建一个单独的测试线程来完成Activity的启动、生命周期调用等,这时候mUiThread就变成了InstrumentationThread了。
- mWindow。属于PhoneWindow类型,mWindow在attach()方法中被创建其标识了当前Activity的屏幕窗口,用户所进行的屏幕交互都是通过这个Window来进行。
- mIntent、mComponent、mActivityInfo。这三者包含了当前Activity的属性信息。
- mBase。属于Context类型,但其实质上是ContextImpl,在Activity的attach()方法中通过attachBaseContext()把传进来的ContextImpl实例赋值给mBase。通过mBase,我们可以访问资源(Asserts、Resources)、进行IO存储(SP、file、database)、使用系统服务等。值得注意的是mBase是其实是Activity父类ContextWrapper的成员变量,这其中还涉及到java设计模式->委托模式的使用,读者可自行研究。
Activity的创建
通常,当我们通过startActivity()通知AMS当前应用需要启动Activity时,AMS在完成服务部分的工作后会通过start时传过去的IApplicationThread(其实是其子类ApplicationThread)来通知应用进程(即ActivityThread)启动Activity。这部分ActivityThread的启动流程如下:

ApplicationThread与H都是ActivityThread的内部类,当我们调用startActivity时其会调用到Instrumentation的execStartActivity()方法。
// frameworks/base/core/java/android/app/Activity.java
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
//...
}
上述方法中,需要重点注意的是第二个参数即mMainThread.getApplicationThread(),这个参数是跨进程用的IBinder类型,其实质上是一个ApplicationThread。
// frameworks/base/core/java/android/app/ActivityThread.java
final ApplicationThread mAppThread = new ApplicationThread();
//...
public ApplicationThread getApplicationThread()
{
return mAppThread;
}
我们通过Instrumentation的execStartActivity()方法把启动Activity的需求发给AMS时,AMS会在调用流程中持续保留这个caller(即ApplicationThread),如果启动的Activity是同一个进程中的,则后续启动结果会直接使用这个caller回传。如果要启动的Activity与调用者不属于同一进程,则AMS会通过Process.start()启动目标进程,进而ActivityThread的main()方法会被调用,在main()方法中会把当前ActivityThread的mAppThread即ApplicationThread通过attachApplication()传给AMS,这样Activity的启动结果AMS同样可以回传给应用进程。
启动Activity最终会回调到ApplicationThread的scheduleLaunchActivity()方法中:
// frameworks/base/core/java/android/app/ActivityThread$ApplicationThread.java
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
//...
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
scheduleLaunchActivity中把由AMS传过来的参数组装成ActivityClientRecord实例并调用ActivityThread的sendMessage()方法转移到主线程(ActivityThread)。
// frameworks/base/core/java/android/app/ActivityThread.java
final H mH = new H();
//...
private void sendMessage(int what, Object obj, int arg1, int arg2,
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
这个转移过程是由H完成的,H类继承自Handler,它作为ActivityThread的全局变量在其创建时初始化。而ActivityThread创建则是在其main()方法中完成的。
// frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
//...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
//...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
}
可以看到的是,ActivityThread在main()方法中被初始化并attach(),而且main()方法中还完成了MainLooper的准备工作,在main()方法调用Looper.loop()时就表明了这个线程进入了消息轮询的过程,这也进一步说明了安卓应用是基于消息机制的,用户与应用的交互、应用内部的功能逻辑都被转换为一条一条的消息交由MainLooper来处理。
正因此,我们在主线程创建的H所转发的消息自然而然就在主线程运行。
在来看scheduleLaunchActivity()中通过sendMessage()转发到H中的消息,这些消息最终会在Handler的handleMessage()中执行(关于Handler机制具体内容可移步到深入理解Handler机制)。
// frameworks/base/core/java/android/app/ActivityThreadA$H.java
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
//...
}
}
在handleMessage()中可以看到把存放在Message中的ActivityClientRecord取出,并调用handleLaunchActivity()方法对这个启动需求进行处理,值得注意的是,上述都是在主线程完成的。handleLaunchActivity()方法如下:
// frameworks/base/core/java/android/app/ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
unscheduleGcIdler();//防止此过程GC,导致ANR
//...
Activity a = performLaunchActivity(r, customIntent);//创建Activity
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
//启resume失败
if (!r.activity.mFinished && r.startsNotResumed) {
//..
}
} else {//如果Activity创建失败,则通知AMS把Activity相关信息移除
try {
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
} catch (RemoteException ex) {
// Ignore
}
}
}
在上述方法中,performLaunchActivity()负责创建Activity并完成必要的初始化工作,而handleResumeActivity()则在Activity初始化后完成Activity的窗口显示部分的工作。如果Activity启动失败,则需要通知AMS启动失败以便其清理Activity在服务端的相关信息。当然,本小节主要讨论的是前者,需进入前者方法中探讨Activity的创建过程。至于resume、pause等过程,其脉络走向与创建过程其实是一致的,读者完全可以举一反三,之后就不在一一介绍了。
// frameworks/base/core/java/android/app/ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
//1. 找出当前要启动Activity具体名称
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
//2. 创建Activity
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
try {
//获取Application
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
//3. Activity的初始化
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.voiceInteractor);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
//4. 生命周期onCreate的调用
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
//5. 生命周期onStart的调用
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
//6. onRestoreInstanceCreate调用,bundle保存在AMS中
if (!r.activity.mFinished) {
if (r.isPersistable()) {
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
r.persistentState);
}
} else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
//7. onPostCreate的调用
if (!r.activity.mFinished) {
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnPostCreate(activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnPostCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPostCreate()");
}
}
}
r.paused = true;
//8. 把Activity放入进程变量中
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}
performLaunchActivity方法可以分为以下八个部分:
- 找出当前要启动Activity具体名称。通过ActivityInfo可以确定当前要启动的ComponentName即组件名,进而要可以根据其中的包名与class名找到Activity。
- 创建Activity实例。需要注意的是,为了创建Activity实例需要使用固定的ClassLoader,即r.packageInfo中的PathClassLoader(这种classloader只能加载已经安装的APK)。在获取到正确的ClassLoader后则通过Instrumentation来进行具体的实例创建。
// frameworks/base/core/java/android/app/Instrumentation.java
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
-
Activity的初始化。在Activity初始化之前,代码中为此准备了以下较为重要的初始化必备实例:
- Application实例。该实例标识了当前进程,为进程单实例,其保存在LoadedApk中。显然地,Application实例不会在Activity创建时才实例化。事实上,当我们Process.start()启动一个新进程时,其最终会调用到ActivityThread的handleBindApplication()方法,而我们的Application实例就是在这个方法中被包裹进LoadedApk进而被添加到ActivityThread全局集合mPackages中去。而此处Activity初始化时则可以通过LoadedApk的makeApplication方法将其取出。
- ContextImpl实例。上述代码中的createBaseContextForActivity()方法即是通过调用ContextImpl生成一个Activity页面上下文。则这上下文即是前边小节中的mBase。
当我们准备好了这两个实例后,接下来就是通过Activity的attach()方法把这些实例添加进去并完成其他诸如窗口、Token等关键Activity成员的初始化。
-
生命周期onCreate()方法的调用。正如之前图示的那样,Activity生命周期方法的调用都是通过Instrumentation来完成的,且在调用前后使用了mCalled变量对onCreate()调用进行检查。
// frameworks/base/core/java/android/app/Instrumentation.java
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
- 生命周期onStart()方法的调用。在Activity的performStart()中,同样使用了Instrumentation的callActivityOnStart()方法来完成生命周期的调用。
// frameworks/base/core/java/android/app/Activity.java
final void performStart() {
//...
mCalled = false;
mFragments.execPendingActions();
mInstrumentation.callActivityOnStart(this);
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onStart()");
}
mFragments.dispatchStart();
//...
}
- onRestoreInstanceCreate调用。
- onPostCreate的调用。
- 把ActivityClientRecord放入进程变量中。mActivities是K-V形式的ArrayMap,它的key是唯一标识Activity的token变量,而value则是封装了Activity的ActivityClientRecord。应用端进程所有的Activity都会被记录到这个map中,后续Activity的pause、stop、destroy流程都会到这个map中根据token查找对应的ActivityClientRecord(其实是ACR中的Activity)来执行对应的应用端流程。
至此,Activity在客户端的启动流程就已完毕,而关于Activity在服务端的启动过程,后边篇章会有介绍。
系统中比较重要的几个Activity
Activity既然具有一个窗口可以与用户进行交互,那么我们有必要思考下安卓桌面页面、任务管理页面是否也属于Activity呢?答案是很显然的,下边我们大概了解下这两个Activity的来龙去脉。(此处介绍这两个Activity一方面也为是后AMS中介绍stack type预热。)
- Launcher。即安卓桌面应用,正如篇首所说的那样,安卓桌面也是一个可与用户交互的Activity,它在AMS起来时被启动。在AMS中启动代码如下:
// frameworks/base/services\core/java/com/android/server/am/ActivityManagerService.java
boolean startHomeActivityLocked(int userId) {
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
&& mTopAction == null) {
return false;
}
Intent intent = getHomeIntent();
ActivityInfo aInfo =
resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
if (aInfo != null) {
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
aInfo = new ActivityInfo(aInfo);
aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
ProcessRecord app = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid, true);
if (app == null || app.instrumentationClass == null) {
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
mStackSupervisor.startHomeActivity(intent, aInfo);
}
}
return true;
}
Launcher的启动是通过Intent隐式启动的,其通过寻找Category匹配Intent.CATEGORY_HOME的Activity启动,正常情况下,系统中配置这个category的只有Launcher应用,但读者也可以配置它,这样如果按home键就可选择想要启动的桌面。
- RecentsActivity。属于SystemUI应用,用于显示最近任务列表,当用户点击switch按键时就会显示。系统在PhoneWindowManager拦截掉用户点按的switch按键并调用StatusBarManagerService的toggleRecentApps()方法。
// frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.javainterceptKeyBeforeDispatching()
else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
if (!keyguardOn) {
if (down && repeatCount == 0) {
preloadRecentApps();
} else if (!down) {
toggleRecentApps();
}
}
return -1;
}
而StatusBarManagerService则因为SystemUI启动时已经通过方法registerStatusBar()注册了IStatusBar接口。这样我们的toggleRecentApps()最后就调用到了BaseStatusBar中的toggleRecentApps中。
// frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@Override
public void toggleRecentApps() {
toggleRecents();
}
这之后经过层层调用,我们的最近任务列表RecentsActivity就被启动起来了。