本文从Activity 创建view,到View的绘制全过程,最终呈现在Activity做一个比较全面的梳理。
1. View在Activity上创建
这里要提到有关Activiy、Window、WindowManager等的相关知识。
ActivityThread 的performLaunchActivity是启动一个Activity的入口,此方法会创建一个Activity。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
//1. 通过反射创建一个acitiviy
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) {
...
}
try {
...
//2. 创建window 对象
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, window);
...
//3. 调用ActivityOncreate方法
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
return activity;
}
在Activity的attach中创建相应的PhoneWindow对象,并设置回调(详见PhoneWindow中Callback接口),此时Activity持有该Window对象
final void attach(Context context, ActivityThread aThread,
Instrumentation instr,...) {
mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
}
当我们在Activity的setContentView方法调用了Window的setContentView ,
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
实际上调用了Window的setContentView
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//1. 构建Decor
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 {
// 2. 将布局inflate到mContentParent上
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
//3. 回调给Activity
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
mContentParent相当于是DecorView的一部分,用来绘制content的部分
private void installDecor() {
...
mContentParent = generateLayout(mDecor);
...
}
protected ViewGroup generateLayout(DecorView decor) {
//其中ID_ANDROID_CONTENT 即com.android.internal.R.id.content
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
return contentParent
}
至此View被添加到顶级View, DecorView上,并显示在Activity的Window上了。
在ActivityThread的handleResumeActivity接口里:
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
...
if (a.mVisibleFromClient && !a.mWindowAdded) {
a.mWindowAdded = true;
// ViewManager的实现ViewManagerImpl 调用WindowManagerGlobal(WindowManager的实现)将DecorView添加到
wm.addView(decor, l);
}
WindowManagerGlobal的addview会
...
root = new ViewRootImpl(view.getContext(), display);
...
root.setView(view, wparams, panelParentView);
其实ViewRootImpl的mView就是顶级View:Decoview 。
至此View被添加DecorView上并进入绘制流程。
2. View的绘制流程
在调用ViewRootImpl的setView中会执行其requestLayout方法
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
}
...
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
//在添加到windowMaganer之前首次执行layout
requestLayout();
}
}
requestLayout会依次调用scheduleTraversals->doTraversal->performTraversals并最终进入绘制流程。
performTraversals会依次调用performMeasure,performDraw, performLayout,并相应的执行mView(DecorView)的measure,draw, layout,
到此view的绘制告一段落了。后面会继续讲到一些view绘制的详细内容