要想优化activity的布局首先应该清楚activity的布局层次。
Activity包含一个phonewindow,phonewindow里面有一个内部类就是DecorView,Decorview是一个FrameLayout,里面包括两个子view,一个是LinearLayout(标题栏加内容),另外一个是底部状态栏。
当Activity启动的时候会通过AMS的ApplictionThreadProxy将创建的消息通过binder驱动发送到应用进程的ApplicationThread中,然后通过handler消息机制将创建Activity的消息发送到主线程中,并调用创建activity的handleLancheActivity方法,通过反射生成Activity对象。
这里主要有两个方面,一个是onCreate方法和onResume方法。
onCreate方法
在调用onCreate之前会创建调用attach方法,创建一个phoneWindow对象。
这里主要讲一下onCreate方法里面的setContentView方法,setContentView其实是调用phoneWindow的setContentView方法。
首先会判断mContentParent的布局是不是null,如果是空则会接着判断decor是不是null,如果decorView也是null,则调用decorview的构造方法,并将自己添加到phonewindow里面,如果不为空则直接添加到phonewindow里面。接着用生成的decorView,去生成mContentParent布局对象,在生成content布局对象的时候也会生成一些decorview的相关对象,例如是否全屏,为解析在style里面设置的属性,例如背景等。
onResume
在onResume方法之后才会真正开始进行绘制和展示绘制的内容,先看一下handleResumeActivity方法
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
// 回调Activity的onResume方法
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
if (r.window == null && !a.mFinished && willBeVisible) {
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
//调用WindowManagerImpl的addView方法
wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
}
} else if (!willBeVisible) {
if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
}
可以看到先回调Activity的onResume方法,之后就会调用WindowManagerImpl的addView方法,最终会调用WindowManagerGlobal的addView,在WindowManagerGlobal里面创建一个ViewRootImpl对象,并调用这个对象的setView把DecorView和ViewRootImpl对象绑定起来。在DecorView的setView主要做了三件事:
第一件:requestLayout刷新布局的操作。
第二件:调用mWindowSession的addToDisplay将Window的添加的工作交给系统WMS来实现。
第三件:对输入事件的处理。
首先分析刷新屏幕布局。
private void performTraversals() {
// 1、relayoutWindow 方法是将mSurface跟WMS关联
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
performLayout(lp, mWidth, mHeight);
performDraw();
}
在绘制的时候需要一个Canvas作为画布,而这个canvas画布则是通过mSurface.lockCanvas获取到。
第二件事:调用mWindowSession.addToDisplay将window的添加工作交给WMS里面,通过WMS来添加window,添加成功则直接将绘制的数据显示在屏幕上。
第三件事:设置以一系列的输入通道。
当硬件驱动发起事件,底层会进行一系列处理,最终会调用InputDispath,会将输入事件分发到需要的地方,例如WindowInputEventReceiver中,最终会调用ViewPostImeInputStage的onPrecess方法,最终调用dispatchPointerEvent,最终会调用DecorView的disPathTouchEvent。调用顺序---->DecorView---->Activity---->PhoneWindow---->DecorView---->ViewGroup。