本文的绘制流程也是基于之前的几篇文章的(同上基于API——15)
1. 安卓应用启动流程分析
2. ActivityThread启动页面分析
3. Activity创建流程分析
上片 Activity创建流程分析说到Activity已经创建了并通过Instrumentation调用了Activity的onCreate方法,那么接下来需要干的事情就很明显了吧,我们在onCreate 的时候一般就是通过setContentView()方法设置布局,设置之后呢,那不知道谁反正是绘制出来了,本文的目的就在于,紧接上文寻找Activity是通过哪些类渲染页面的
setContentView()
public void setContentView(int layoutResID) {
// 各位大爷 真是基于api 15 的,高版本的 不一样的
//getWindow 获取到当前绑定的Window window本身就是一套接口,我们看的是具体实现的地方,上文attach方法提到了
//创建的window是PhoneWindow 源码在Policy类里面,
getWindow().setContentView(layoutResID);
initActionBar();
}
进入PhoneWindow
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
//这个逻辑已经不能再清晰了,最终我们写的View要添加到mContentParent中,他是一个ViewGroup
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
首先查看mContentParent 是如何创建的
private void installDecor() {
if (mDecor == null) {
// 这里就是直接new DecorView(getContext(), -1); new了一个DecorView
mDecor = generateDecor();
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
}
if (mContentParent == null) {
//到这个方法才生成,下面进入查看
mContentParent = generateLayout(mDecor);
mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
if (mTitleView != null) {
if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
View titleContainer = findViewById(com.android.internal.R.id.title_container);
if (titleContainer != null) {
titleContainer.setVisibility(View.GONE);
} else {
mTitleView.setVisibility(View.GONE);
}
if (mContentParent instanceof FrameLayout) {
((FrameLayout)mContentParent).setForeground(null);
}
} else {
mTitleView.setText(mTitle);
}
} else {
//处理id是ActionBar 这里就不看了
}
}
}
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
TypedArray a = getWindowStyle();
//根据当前的主题设置窗口属性
......
// Inflate the window decor.
int layoutResource;
int features = getLocalFeatures();
//根据当前的窗口属性选择相对应的布局
......
//将相应的布局文件转成view添加到窗口视图对象decor中
View in = mLayoutInflater.inflate(layoutResource, null);
//这里我们可以断定 DecoreView(本身就是一个Framelayout)就是我们的顶层View 了,
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
//这个不就是我们的容器吗 我们最终的View是添加到这个View里面的
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
......
return contentParent;
}
以上的分析我们只是看到了 setContentView最终是把我们的View填充了,但是我们来此的目的并不只是如此吧,我们还想知道 具体的绘制流程,谁绘制的还记得我们的performMeasure 。。 等那三个方法吗,现在还没有看到啊,大胸弟,onCreate方法里面就这么多,说明还没有到绘制的那一步啊,那么在哪里进行绘制的呢?当然是生命周期的onReuse之前绘制完成不就好了,那我们去看看。
handleResumeActivity
上文Activity创建流程分析 走了handleLaunchActivity中我们是不是又handleResumeActivity 对吧,这个很明确了,首先handleLaunchActivity 调用了onCreate方法,里面把布局什么的如上添加好,但只是吧资源文件加载了,还没有进行最终的绘制,下面看 handleResumeActivity如何绘制
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
// 略去。。。
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;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
//获取到WindowManager 然后通过他添加了一个View,那么说明绘制不在Activity 中,而是交给了WindowManager
wm.addView(decor, l);
}
// 略去。。。
//还记得之前activity 的attach方法吗,有提到 PhoneWindow 而获取WindowManager mWindow.getWindowManager(); 不就是他
我们进入到 PhoneWindow的这个方法看她如何操作
mWindow.setWindowManager(null, mToken, mComponent.flattenToString(),(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
WindowManager设置与获取
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
//从这里获取到一个WindowManager的实例
wm = WindowManagerImpl.getDefault();
}
mWindowManager = new LocalWindowManager(wm, hardwareAccelerated);
}
那么我们的WindowManager 的对象找到了,紧接着上文的addView方法,我们继续追踪
private void addView(View view, ViewGroup.LayoutParams params,
CompatibilityInfoHolder cih, boolean nest) {
final WindowManager.LayoutParams wparams
= (WindowManager.LayoutParams)params;
ViewRootImpl root;
View panelParentView = null;
synchronized (this) {ocked(view, false);
if (index >= 0) {
root = mRoots[index];
root.mAddNesting++;
view.setLayoutParams(wparams);
root.setLayoutParams(wparams, true);
return;
}
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews != null ? mViews.length : 0;
for (int i=0; i<count; i++) {
if (mRoots[i].mWindow.asBinder() == wparams.token) {
panelParentView = mViews[i];
}
}
}
//创建了ViewRootImpl 他也是真正的执行者
root = new ViewRootImpl(view.getContext());
root.mAddNesting = 1;
view.setLayoutParams(wparams);
if (mViews == null) {
index = 1;
mViews = new View[1];
mRoots = new ViewRootImpl[1];
mParams = new WindowManager.LayoutParams[1];
} else {
index = mViews.length + 1;
Object[] old = mViews;
mViews = new View[index];
System.arraycopy(old, 0, mViews, 0, index-1);
old = mRoots;
mRoots = new ViewRootImpl[index];
System.arraycopy(old, 0, mRoots, 0, index-1);
old = mParams;
mParams = new WindowManager.LayoutParams[index];
System.arraycopy(old, 0, mParams, 0, index-1);
}
index--;
mViews[index] = view;
mRoots[index] = root;
mParams[index] = wparams;
}
// root ? 是什么 他是 ViewRootImpl 最终的操作又交给了 他
root.setView(view, wparams, panelParentView);
}
进入ViewRootImpl
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
//除了这行其他的全部省略,其中包括和WindowManagerService的通信,留着以后讲,今天就看绘制流程。
requestLayout();
}
}
public void requestLayout() {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
//最终会进入到这个方法 ,我天是不是很熟悉,我们最常说道的 performMeasure performLayout performDraw ,没错就是在这里进行的
private void performTraversals() {
......
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
......
performDraw();
}
......
}
见到这里的时候我们就已经很清楚了
- Activity attach 方法创建了PhoneWindow 以及WindowManager
- Activity的onCreate 方法里面主要是对setContentView的处理,把布局挂到根布局上
- handleResumeActivity 利用了WindowManager 以及ViewRootImpl 对已经设置好的布局进行绘制。到这里,我们Activity的启动流程到最终绘制 已经完成了!
以上几篇文章都是本人用sourseInsight 边看源码一边撸的,如果有错误的地方还请指出来!
本文详细探讨了Android Activity的绘制流程,从setContentView()开始,经过PhoneWindow的创建,到handleResumeActivity的调用,进一步分析了WindowManager的设置与获取,最后进入ViewRootImpl进行布局的绘制。在onCreate()方法中,主要处理setContentView,而在handleResumeActivity中,利用WindowManager和ViewRootImpl完成了最终的绘制工作。


被折叠的 条评论
为什么被折叠?



