本文将会带你深入了解Activity生命周期。
首先,抛出几个问题
- Activity的生命周期是怎么实现的?
- 在每个生命周期中,做了那些事情?
- 我们如何合理的使用Activity生命周期,编写更健壮的程序?
接下来,我们会对每个问题进行解答。
1. Activity的生命周期是怎么实现的?
Activity本身没有main方法入口,而管理Activity生命周期的线程ActivityThread中有main方法,通过ActivityThread线程结合handler机制实现生命周期的回调。我们以回调onCreate生命周期为例,进入源码一览谷歌工程师的风采。
- 首先找到Activity.java,其中声明了ActivityThread对象。故我们知道Activity的生命周期回调是靠ActivityThread来实现的。
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback, WindowControllerCallback,
AutofillManager.AutofillClient {
private static final String TAG = "Activity";
private Instrumentation mInstrumentation;
//Instrumentation后面会介绍
private IBinder mToken;
//底层通信是靠Ibinder进行的
private Application mApplication;
Intent mIntent;
String mReferrer;
private ComponentName mComponent;
ActivityInfo mActivityInfo;
//重要的就是这里有ActivityThread对象,是主线程。
//Activity的回调是靠ActivityThread和Handler结合实现的。
ActivityThread mMainThread;
Activity mParent;
- 第二步,我们需要找到ActivityThread类,瞧一瞧他做了些什么,又是怎么回调Activity生命周期的,那我们从ActivityThread的main方法入手分析。
public static void main(String[] args) {
//省略一些与环境相关的代码
Looper.prepareMainLooper();
//获取主线程的looper
ActivityThread thread = new ActivityThread();
//实例化一个thread
thread.attach(false);
//这个attach方法需要重点关注
//这里就是为什么我们在主线程中使用Handler不需要调用Looper.prepareLooper()方法,因为
//初始化的时候就已经获取了,但是如果我们要在子线程中使用handler,就需要获取looper。
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
- 第三步,在main方法中,做了一些初始化的工作,实例化一个线程,并获取looper,但是我们好像还是没看见和生命周期相关的代码,别急,我们继续探索,看看attach方法中做了什么?
private void attach(boolean system) {
//省略一些代码
final IActivityManager mgr = ActivityManager.getService();
//ActivityManager从字面上理解,Activity的管家,
try {
//mAppThread是一个ActivityThread的内部类,ApplicationThread,等会我们会详细的看这一个类的细节。
mgr.attachApplication(mAppThread);
//这行代码,让mAppThread和Activity产生关联?我们暂时这样猜测,深入该方法求证。
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
//ConfigChangedCallback 就是相关配置发生变化时的回调,当我们旋转屏幕,切换语言时就会回调该方法。
ViewRootImpl.ConfigChangedCallback configChangedCallback
= (Configuration globalConfig) -> {
synchronized (mResourcesManager) {
if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
null /* compat */)) {
updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
mResourcesManager.getConfiguration().getLocales());
// This actually changed the resources! Tell everyone about it.
if (mPendingConfiguration == null
|| mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
mPendingConfiguration = globalConfig;
sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
//发送通知,告知handler去处理这个配置变化,重建Activity.
}
}
}
};
//为整个View添加这个回调,这也是为什么我们的配置发生变化,Activity会被重建的原因。
ViewRootImpl.addConfigCallback(configChangedCallback);
}
- 第四步,上一步中我们猜测attachApplication方法让applicationThread的一个实例和Activity产生关联,但是这样做有什么用?我们想要的生命周期回调到底在哪呢?沉住气,我们很快就能看见他的庐山真面目了。让我们再看看attachApplication方法,这个方法在ActivityManagerService中。
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
//pid进程号
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
//我们好像没有得到任何有用的信息,这里又出现了attachApplicationLocked
//还出现一个进程号,不妨再猜测让application线程绑定一个进程?好像也说的通,再进去看看
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
//我们可以认为前面的方法做了一些与系统环境相关的事情
if (normalMode) {
try {
if (mStackSupervisor.attachApplicationLocked(app)) {
//重点就是mStackSupervisor.attachApplicationLocked(app)
//不妨看看到底他是何方神圣
didSomething = true;
}
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
//省略前面的一些代码,这里我们看见app.thread.scheduleLaunchActivity
//翻译过来就是计划启动一个Activity,启动了,那是不是离我们的onCreate生命周期不远了呢?再去探探。这里的thread是ApplicationThread,所以我们要去ActivityThread中寻找,他是ActivityThread中的一个内部类。
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
return true;
}
- 第五步,经过一系列崎岖转折,我们终于到了启动Activity的地方,下面非常精彩,大家坚持住!
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
//根据传递过来的参数,构建一个ActivityClientRecord
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
//利用Handler发送这个信息,让hanldermessage去处理。
sendMessage(H.LAUNCH_ACTIVITY, r);
}
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
//接收传递过来的ActivityClientRecord
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
//在这里执行启动Activity操作
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
}
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
//创建一个Activity.
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
//为什么这里要判断activity是不是为空?如果之前已经创建过
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
if (!r.activity.mFinished && r.startsNotResumed) {
performPauseActivityIfNeeded(r, reason);
if (r.isPreHoneycomb()) {
r.state = oldState;
}
}
} else {
try {
ActivityManager.getService()
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//个人认为performLaunchActivity里面的代码都非常重要,但是为了不绕晕大家,我们只沿着主线进行。
if (r.isPersistable()) {
//在这里我们看见了一个期盼已久的字眼,onCreate,通俗理解为
//叫Activity执行OnCreate回调,这可太棒了。
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;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
mActivities.put(r.token, r);
return activity;
}
public void callActivityOnCreate(Activity activity, Bundle icicle,
PersistableBundle persistentState) {
prePerformCreate(activity);
activity.performCreate(icicle, persistentState);
//调用activity.performCreate(icicle, persistentState)执行onCreate
postPerformCreate(activity);
}
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
mCanEnterPictureInPicture = true;
restoreHasCurrentPermissionRequest(icicle);
if (persistentState != null) {
onCreate(icicle, persistentState);
} else {
onCreate(icicle);
//这里,回调onCreate,完成。
}
mActivityTransitionState.readState(icicle);
mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
mFragments.dispatchActivityCreated();
mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
}
绕了一大圈,从Activity中的ActivityThread的main方法出发,经过一些配置,配合handler最终找到回调onCreate方法,onCreate只是一个案例,其他的生命周期回调也是靠ActivityThread和handler配合完成的。这里我们深入了解了Activity的生命周期是如何执行的,执行onCreate方法中,还会执行setContentView(),这是整个Ui绘制的起点,也可以根据源码了解整个详情。
2. 谈谈每个生命周期
-
onCreate
必须实现此回调,其在系统首次创建 Activity 时触发。Activity 会在创建后进入已创建状态。在 onCreate() 方法中,需执行基本应用启动逻辑,该逻辑在 Activity 的整个生命周期中只应发生一次。例如,onCreate() 的实现可能会将数据绑定到列表,将 Activity 与 ViewModel 相关联,并实例化某些类范围变量。此方法接收 savedInstanceState 参数,后者是包含 Activity 先前保存状态的 Bundle 对象。如果 Activity 此前未曾存在,则 Bundle 对象的值为 null。 -
onStart
当 Activity 进入“已开始”状态时,系统会调用此回调。onStart() 调用使 Activity 对用户可见,因为应用会为 Activity 进入前台并支持交互做准备。例如,应用通过此方法来初始化维护界面的代码。
当 Activity 进入已开始状态时,与 Activity 生命周期相关联的所有具有生命周期感知能力的组件都将收到 ON_START 事件。
onStart() 方法会非常快速地完成,并且与“已创建”状态一样,Activity 不会一直处于“已开始”状态。一旦此回调结束,Activity 便会进入已恢复状态,系统将调用 onResume() 方法。 -
onResume
Activity 会在进入“已恢复”状态时来到前台,然后系统调用 onResume() 回调。**这是应用与用户交互的状态。应用会一直保持这种状态,直到某些事件发生,让焦点远离应用。**此类事件包括接到来电、用户导航到另一个 Activity,或设备屏幕关闭。
当 Activity 进入已恢复状态时,与 Activity 生命周期相关联的所有具有生命周期感知能力的组件都将收到 ON_RESUME 事件。这时,生命周期组件可以启动任何需要在组件可见,且位于前台时运行的功能,例如启动摄像头预览。
当发生中断事件时,Activity 进入已暂停状态,系统调用 onPause() 回调。
如果 Activity 从“已暂停”状态返回“已恢复”状态,系统将再次调用 onResume() 方法。因此,应实现 onResume(),以初始化在 onPause() 期间释放的组件,并执行每次 Activity 进入“已恢复”状态时必须完成的任何其他初始化操作。 -
onPause
系统将此方法视为用户正在离开 Activity 的第一个标志(尽管这并不总是意味着活动正在遭到销毁);此方法表示 Activity 不再位于前台(尽管如果用户处于多窗口模式,Activity 仍然可见)。使用 onPause() 方法暂停或调整当 Activity 处于“已暂停”状态时不应继续(或应有节制地继续)的操作,以及希望很快恢复的操作。还可以使用 onPause() 方法释放系统资源、传感器(例如 GPS)手柄,如果处于多窗口模式,则“已暂停”的 Activity 仍完全可见。因此,应该考虑使用 onStop() 而非 onPause() 来完全释放或调整与界面相关的资源和操作,以便更好地支持多窗口模式。onPause() 执行非常简单,而且不一定要有足够的时间来执行保存操作。因此,不应使用 onPause() 来保存应用或用户数据、进行网络调用,或执行数据库事务。因为在该方法完成之前,此类工作可能无法完成。相反,您应在 onStop() 期间执行高负载的关闭操作。 -
onStop
如果 Activity 不再对用户可见,则说明其已进入已停止状态,**因此系统将调用 onStop() 回调。**举例而言,如果新启动的 Activity 覆盖整个屏幕,就可能会发生这种情况。如果系统已结束运行并即将终止,系统还可以调用 onStop()。
当 Activity 进入已停止状态时,与 Activity 生命周期相关联的所有具有生命周期感知能力的组件都将收到 ON_STOP 事件。这时,生命周期组件可以停止任何无需在组件未在屏幕上可见时运行的功能。
在 onStop() 方法中,应用应释放或调整应用对用户不可见时的无用资源。例如,应用可以暂停动画效果,或从细粒度位置更新切换到粗粒度位置更新。使用 onStop() 而非 onPause() 可确保与界面相关的工作继续进行,即使用户在多窗口模式下查看您的 Activity 也能如此。 进入“已停止”状态后,Activity 要么返回与用户交互,要么结束运行并消失。如果 Activity 返回,系统将调用 onRestart() 方法。如果 Activity 结束运行,系统将调用 onDestroy()。 -
onDestory
销毁 Ativity 之前,系统会先调用 onDestroy()。系统调用此回调的原因如下:
1.Activity 正在结束(由于用户彻底关闭Activity 或由于系统为 Activity 调用 finish()))
- 由于配置变更(例如设备旋转或多窗口模式),系统暂时销毁
Activity
当 Activity 进入已销毁状态时,与 Activity 生命周期相关联的所有具有生命周期感知能力的组件都将收到 ON_DESTROY 事件。此时,生命周期组件可以在 Activity 遭到销毁之前清理所需的任何数据。
**应使用 ViewModel 对象来容纳 Activity 的相关视图数据,而不是在Activity 中加入逻辑来确定 Activity 遭到销毁的原因。**如要由于配置变更而重新创建 Activity,则 ViewModel 不必执行任何操作,因为系统将保留 ViewModel 并将其提供给下一个 Activity 实例。如果不重新创建 Activity,ViewModel 将调用 onCleared() 方法,以便在 Activity 遭到销毁前清除所需的任何数据。
如果 Activity 正在结束,则 onDestroy() 是 Activity 收到的最后一个生命周期回调。如果由于配置变更而调用 onDestroy(),则系统会立即新建 Activity 实例,然后在新配置中为新实例调用 onCreate()。
onDestroy() 回调应释放先前的回调(例如 onStop())尚未释放的所有资源。
3. 我们如何合理的使用Activity生命周期,编写更健壮的程序?
1.保存界面的状态和恢复
这种情况比较常见,比如说用户在使用我们的软件,突然收到一条QQ信息,跳转到QQ去了,然后再回到我们应用的时候,可能之前输入的信息没有被保存丢失了,因此我们需要做界面状态的保存和恢复。
如果系统因系统约束(例如配置变更或内存压力)而销毁 Activity,则虽然实际的 Activity 实例已消失,但系统会记住它曾经存在过。如果用户尝试回退到该 Activity,则系统将使用一组描述 Activity 销毁时状态的已保存数据新建该 Activity 的实例。
系统用于恢复先前状态的已保存数据称为实例状态,是存储在 Bundle 对象中的键值对集合。默认情况下,系统使用 Bundle 实例状态来保存 Activity 布局中每个 View 对象的相关信息(例如在 EditText 微件中输入的文本值)。这样,如果您的 Activity 实例被销毁并重新创建,布局状态便会恢复为其先前的状态,且您无需编写代码。但是,您的 Activity 可能包含您要恢复的更多状态信息,例如追踪用户在 Activity 中的进程的成员变量。
2.使用 onSaveInstanceState() 保存简单轻量的界面状态
当 Activity意外 开始停止时,系统会调用 onSaveInstanceState() 方法,以便您的 Activity 可以将状态信息保存到实例状态 Bundle 中。此方法的默认实现保存有关 Activity 视图层次结构状态的瞬态信息,例如 EditText 微件中的文本或 ListView 微件的滚动位置。
如要保存 Activity 的其他实例状态信息,必须替换 onSaveInstanceState(),并将键值对添加到您Activity 意外销毁时所保存的 Bundle 对象中。替换 onSaveInstanceState() 时,如果希望默认实现保存视图层次结构的状态,则必须调用父类实现。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
currentScore = savedInstanceState.getInt(STATE_SCORE);
currentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
// ...
}