您的位置:首页 > 移动开发 > Android开发

android之View绘制到窗口上的过程

2015-03-30 23:32 399 查看
以前在研究自定义空间的时候,查看过View和ViewGroup绘制的流程的。只是定性的知道会经过onMeasure—onLayout—onDraw这些流程。上一篇Android视图加载到窗口的过程分析中分析了视图加载到窗口的过程。主要就是一系列的addView操作,这篇就从addView方法开始看看View是如何绘制到窗口上的。

ActivityThread#handleResumeActivity方法

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
boolean reallyResume) {
……
ActivityClientRecord r = performResumeActivity(token, clearHide);
……
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();//前面分析过,这个是Window对象所维护的装饰窗口,最顶层的窗口
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();//获取WindowManager,继承自ViewManager,不可实例化,是个接口
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;
wm.addView(decor, l);// 通过WindowManager添加到窗口
}
……
}

可以看到最顶层的装饰窗口在activity resume的时候通过windowManager#addView方法添加。

WindowManagerImpl# addView

public void addView(View view, ViewGroup.LayoutParams params) {
mGlobal.addView(view, params, mDisplay, mParentWindow);
}

public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {

ViewRootImpl root;
View panelParentView = null;
......
root = new ViewRootImpl(view.getContext(), display); // 创建一个ViewRoot对象

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;// 将view和ViewRootImp关联起来  ViewRootImp是链接View和WindowManagerService的桥梁
mParams[index] = wparams;
}
try {
root.setView(view, wparams, panelParentView);// 调用ViewRoot的setView方法
}
......
}


setView:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
requestLayout(); // 请求UI开始绘制重新绘制View树
......
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
// 通知WindowManagerService添加一个窗口  会调用到addWindow方法
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mInputChannel);
}
}

两种情况会导致调用到requestLayout,改变视图显示属性,比如setVisibility,是直接或者间接调用该函数。

@Override
public void requestLayout() {
checkThread();// 本次调用是否是在UI线程调用的。
mLayoutRequested = true;
scheduleTraversals();
}

void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
//分发一个异步消息,处理函数中调用performTraversals()对View进行重新遍历。
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);// mTraversalRunnable是一个Runnable对象
scheduleConsumeBatchedInput();
}
}

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();//执行doTraversal()
}
}

void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
……
try {
performTraversals();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
……
}
}

View树遍历的核心函数 measure—layout--draw

private void performTraversals() {
......
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
......
performLayout();
……
performDraw();
……
mIsInTraversal = false;
}


private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}


mView.measure(childWidthMeasureSpec,childHeightMeasureSpec);就执行到了熟悉onMeasure(childWidthMeasureSpec,childHeightMeasureSpec);里面。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: