网上有一个总结我觉得很清晰:
我们今天的主题就是
View是如何绘制出来的?
我们知道我们Application的核心载体是Activity(界面),而View是用户可见的并且可以交互的内容。
我们知道View通过measure确定打下,layout确定位置,draw绘制到屏幕上。
今天就从View如何绘制到屏幕上进行分析
画图
setContentView
// Activity.java
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
}
其中细节我们不展开,很多文章都说这里的getWindow实现PhoneWindow代表一个Window,我个人认为这个PhoneWindow只是一个方便管理View的类而已,它和Android的Window概念不相关。
setContentView做了几件事情:
- 初始化DecoreView
- 将layoutResID通过inflate生成一棵View树(后续展开)
- 将View添加到DecorView里面(FrameLayout)
在ActivityThread.handleResume方法中真正进行View的展示:
// ActivityThread.java
@Override
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
boolean isForward, String reason) {
//伪代码
WindowManager.LayoutParams l = r.window.getAttributes();
//wm就是WindowManager
wm.addView(decor, l);
}
到这里我们也开始跳过:
WM.addView做了几件事情:
- 创建了ViewRootImpl对象
- 调用ViewRootImpl.setView方法
稍微看到这个setView方法:
- requestLayout触发performTravals
- 通过WindowManangerService添加window
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
requestLayout();
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets,
mTempControls);
}
}
到这里我们简单总结下:
1、 我们的View创建后通过WindowManagerService封装成一个Window管理起来 2、触发ViewRootImple的performTravals进行我们熟悉的View的三步骤 measure/layout/draw
private void performTraversals() {
//1 设置window的大小
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
//2 测量view的大小
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
//3 设置位置
performLayout(lp, mWidth, mHeight);
//4 绘制
performDraw();
}
在绘制时:
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
canvas = mSurface.lockCanvas(dirty);
mView.draw(canvas);
surface.unlockCanvasAndPost(canvas);
return true;
}
具体细节其他文章会分析,到这里 Surface.locaCanvas就是我们熟悉的方法。
1、Surface是ViewRootImpl创建的一个对象,这里可以知道一个Window(这里的Window不是PhoneWindow,而是View的集合概念,WindowManagerService管理的WindowState)对应一个ViewRootImpl,一个Surface。 2、 Surface的lockCanvas方法会通过Native的Surface获取GraphicBuffer对象,再通过Canvas进行数据填充。这就是我们之前写的生产者往BufferQueue中dequeueBuffer获取GraphicBuffer,queueBuffer塞入队列的过程。
里面的细节,我们单开文章再讲解.
未完待续....