一切从setContentView方法开始
源码把布局文件设置给window对象
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
那么查看window的setContentView方法
@Override
public void setContentView(int layoutResID) {
//mContentParent为null,执行installDecor方法。
if (mContentParent == null) {
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 {
//把布局添加到mContentParent中
mLayoutInflater.inflate(layoutResID, mContentParent);
}
...
}
mContentParent又是什么?
跟踪installDecor方法
private void installDecor() {
//创建Decor对象
if (mDecor == null) {
mDecor = generateDecor(-1);
}
if (mContentParent == null) {
//获取mContentParent对象
mContentParent = generateLayout(mDecor);
}
...
}
接着跟踪generateLayout方法
protected ViewGroup generateLayout(DecorView decor) {
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
return contentParent;
}
至此,我们初始化了DecorView布局,并且把我们布局文件加载到了DecorView中。
同时实例化了Window
我们回到开始,去查找Window对象在哪里创建的,通过源码可以发现在Activity#attach中对其进行了赋值操作(在Activity启动过程中,会执行ActivityThread#performLaunchActivity方法,在这个方法中会调用Activity#attach方法)。
在Activity在启动流程中当执行了ActivityThread#performLaunchActivity方法后还会执行ActivityThread#handleResumeActivity方法,在这个方法中首先会调用Activity的onResume方法,接着调用Activity的makeVisible方法。
void makeVisible() {
if (!mWindowAdded) {
//获取WindowManager
ViewManager wm = getWindowManager();
//通过WindowManager完成window和DecorView的关联
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);//然后让布局显示
}
那么WindowManager是怎么完成window和DecorView的关联的呢?
继续跟踪源码,找windowManager类中的addView方法,windowManager是一个接口,我们找他的实现类WindowManagerImpl
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
发现WindowManagerImpl#addView并没有实现具体细节,而是交WindowManagerGlobal中的addView去处理。
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
ViewRootImpl root;
synchronized (mLock) {
// 实例化ViewRootImpl,它是WindowManager和DecorView的处理类
root = new ViewRootImpl(view.getContext(), display);
//这是布局参数
view.setLayoutParams(wparams);
mViews.add(view);//保存所有Window对应的View
mRoots.add(root);//保存所有Window对应的ViewRootImpl
mParams.add(wparams);//保存所有Window对应的布局参数
}
try {
//接着调用ViewRootImpl中的setView方法
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
}
}
注意:WindowManagerGlobal类里边有所有View的对象。
接着来看ViewRootImpl#setView方法
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
//内部最终会调用performTraversals方法开启View的绘制流程。
requestLayout();
try {
//通过IWindowSession来完成Window的添加过程,这是和系统的IPC过程,我分析不出来了
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} catch (RemoteException e) {
} finally {
}
}
}
}
看怎么开启绘制的还是可以分析出来的
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
//调用这个方法
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//发送runnable
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
private void performTraversals() {
...
//执行测量
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
//执行布局
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
...
//执行绘制
performDraw();
}
在performTraversals方法依次会执行performMeasure、performLayout以及performDraw来完成对顶级View的测量、布局、绘制。
- 把布局挂载到DecorView中
- 通过WindowManager添加到window到屏幕上(ipc过程不会分析)
- 通过ViewRootImpl完成window和DecorView的关联(Ipc过程不会分析)
- ViewRootImpl中去触发performTraversals去执行测量,布局,和绘制的执行
那么我们就可以说activity中的setContentView方法出发了ViewRootImpl类中的performTraversals去执行测量布局和绘制。