面试必备,从源码角度分析UI绘制流程(上)

版权声明:本文为博主原创文章,转载请标注 https://blog.csdn.net/cai784921129/article/details/82183884

Activity如何加载布局的?我们定位到Activity.java

Avtivity调用setContentView,

public void setContentView(@LayoutRes int layoutResID) {

getWindow().setContentView(layoutResID);

initWindowDecorActionBar();

}

public Window getWindow() {

return mWindow;

}

getWindow得到的是 mWindow,它是Window对象,Window是一个抽象类,它提供了各种窗口操作、设置背景的方法。

我们再全局搜索mWindow是在哪初始化的

final void attach(...) {

...

mWindow = new PhoneWindow(this, window);

mWindow.setWindowControllerCallback(this);

mWindow.setCallback(this);

mWindow.setOnWindowDismissedCallback(this);

mWindow.getLayoutInflater().setPrivateFactory(this);

...

}

可以看到mWindow是由PhoneWindow实现的

现在知道Activity的onContentView调用的是PhoneWindow的onContentView,我们再来看一下PhoneWindow的onContentView方法(这个类被隐藏了,小伙伴可以取sources目录全局搜索)

@Override

public void setContentView(int layoutResID) {

if (mContentParent == null) {

installDecor();

} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

mContentParent.removeAllViews();

}



if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

view.setLayoutParams(params);

final Scene newScene = new Scene(mContentParent, view);

transitionTo(newScene);

} else {

mContentParent.addView(view, params);

}
...


cb.onContentChanged();



}

现在逐一分析PhoneWindow的onContentView方法,先看installDecor()

private void installDecor() {

if (mDecor == null) {

mDecor = generateDecor(-1);

...

} else {

mDecor.setWindow(this);

}

if (mContentParent == null) {

mContentParent = generateLayout(mDecor);

...

}

接着看下generateDecor(-1)

protected DecorView generateDecor(int featureId) {

Context context;

...

return new DecorView(context, featureId, this, getAttributes());

}

DecorView extends FrameLayout

DecorView(Context context, int featureId, PhoneWindow window,

WindowManager.LayoutParams params) {

super(context);

...

setWindow(window);//与phoneWindiw绑定

...

}

就是new了一个DecorView

接着分析installDecor方法

if (mContentParent == null)

mContentParent = generateLayout(mDecor);

generateLayout是什么作用呢?

protected ViewGroup generateLayout(DecorView decor) {

...

mDecor.startChanging();

mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);



ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

...



mDecor.finishChanging();



return contentParent;

}

看一下mDecor的onResourcesLoaded(mLayoutInflater, layoutResource)方法;

void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {

...

final View root = inflater.inflate(layoutResource, null);

addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));

...

}

可以看到onResourcesLoaded方法目的是把 包含id为ID_ANDROID_CONTENT的布局文件,添加到DecoverView里。

generateLayout返回的contentParent其实就是ID为ID_ANDROID_CONTENT的FrameLayout

现在知道了installDecor();其实就是创建DecoverView和mContentParent,并将mContentParent添加到mDecor里面。

@Override

public void setContentView(int layoutResID) {

installDecor();//初始化DecorView,向DecoverView添加系统布局,获取其中id为content的帧布局

mContentParent.addView(view, params);//将我们的布局添加到帧布局中

final Callback cb = getCallback();

if (cb != null && !isDestroyed()) {

cb.onContentChanged();

}

}

关键点

mContentParent.addView(view, params);

将用户定义的view添加到mContentParent中,然后回调onContentChanged方法,可在Avtivity中重写这个接口,代表布局加载完成的回调

setContentView主要作用有两个

1、初始化DecorView,向DecoverView添加系统布局,获取其中id为content的帧布局

2、将我们的布局添加到帧布局中

我们窗口分布大致如下

窗口分层

猜你喜欢

转载自blog.csdn.net/cai784921129/article/details/82183884
今日推荐