概述
最近去面试,被问到Activity的启动机制,顿时一脸懵逼,什么鬼!回来后就决定了要看下源码,学习下Activity启动相关的知识。
启动过程介绍
Activity的启动是从ActivityThread开始的,我们直接来看下ActivityThread的代码。代码过长只挑重点的看
public static void main(String[] args) {
....(此处省略一万行代码)....
// 原来Looper的初始化和线程绑定在这里做了,所以我们在UI线程里可以直接用handler,如果是在线程中就要自己调用prepare()和loop()。
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 触发事件循环
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
这里只是ActivityThread的开始而已,Activity呢?ActivityThread里有个Handler的实现,里面收到LAUNCH_ACTIVITY消息后会调用handleLaunchActivity(r, null)进入处理启动相关事项,我们看这个函数
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
....(此处省略一万行代码)....
// Initialize before creating the activity
// 初始化WindowManagerGlobal,用于后面addView用的,只需要知道window是一个窗户,透明的窗户,后面还是要填充玻璃的
WindowManagerGlobal.initialize();
// 这里能过performLaunchActivity创建了一个Activity实例
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
// 这里执行了Activity的resume,create呢?在performActivity里面已经做好了
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
....(此处省略一万行代码)....
}
} else {
// If there was an error, for any reason, tell the activity
// manager to stop us.
try {
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
} catch (RemoteException ex) {
// Ignore
}
}
}
通过performLaunchActivity创建Activity成功后就执行了handleResumeActivity,就是进入Activity的onResume状态了,那创建初始化的过程我们再看看performLaunchActivity里的具体实现
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
....(此处省略一万行代码)....
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
// 这里通过mInstrumentation生成了一个Activity实例,后面Activity状态也是由mInstrumentation来管理的
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);
}
}
....(此处省略一万行代码)....
if (activity != null) {
....(此处省略一万行代码)....
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor);
....(此处省略一万行代码)....
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
}
}
....(此处省略一万行代码)....
return activity;
}
attach后面就调用了callActivityOnCreate,就进入了Activity的onCreate状态,那attach里面又做了什么,我们再跟进去看下
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
// 实例化window对象,有了window就有了activity内容的载体了
mWindow = new PhoneWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
if (voiceInteractor != null) {
if (lastNonConfigurationInstances != null) {
mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
} else {
mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
Looper.myLooper());
}
}
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
其实这段代码就是初始化window,为后面加载activity内容做准备,刚才也说了,attach后就进入了Activity的onCreate状态,在onCreate里就调用了我们常见的setContentView了。
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
setContentView其实就是调用刚才attach里初始化的window里的setContentView方法,我们再看PhoneWindow里setContentView的实现
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
// 初始化DecorView
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
// 加载我们的layout到mContentParent中
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
....(此处省略一万行代码)....
}
}
protected ViewGroup generateLayout(DecorView decor) {
....(此处省略一万行代码)....
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
....(此处省略一万行代码)....
}
setContentView的时候,调用了installDecor方法,以及mLayoutInflater.inflate(layoutResID, mContentParent);把我们的布局加载到mContentParent中。但mContentParent从哪里来?在installDecor里,通过generateLayout把我们的内容区域添加进去了,我们看到了熟悉的ID_ANDROID_CONTENT,就是我们的内容区域。
总结
看完这些代码后,对Activity的启动流程有了一个大概的了解。总的来说就是通过IPC调用AMS里startActivity,然后在ActivityThread的handleLanchActiivyt里先初始化window,实际是PhoneWindow;然后就调用了Activity的onCreate,setContentView就是调用phoneWindow的setContentView,里面初始化了decorView,decorView是phoneWindow的变量,继承自FrameLayout,是我们整个view的根布局,里面有一个ContentViewGroup的区域是用来加载我们的layout的。加载我们的Layout后,通过WindowManager把window添加进去,显示到界面上。可以说window就是一个透明的窗户区域,decorView就是窗户的边框,有固定的一些东西(ActionBar、Title),layout就是我自定义的窗户,可以雕花可以贴纸。自己的理解,不喜勿喷。