看一下mTraversalRunnable
- final class TraversalRunnable implements Runnable {
- @Override
- public void run() {
- doTraversal();
- }
- }
- final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
-
- void doTraversal() {
- if (mTraversalScheduled) {
- mTraversalScheduled = false;
- mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
- performTraversals();
- }
- }
在TraversalRunnable中,执行doTraversal.并在doTraversal执行performTraversals(),是不是看到了我们熟悉的performTraversals()了?是的,在这里才开始View的绘制工作.
在ViewRootImpl中的performTraversals(),这个方法代码很长(大约800行代码),大致流程是
- 判断是否需要重新计算视图大小,如果需要就执行performMeasure()
- 是否需要重新安置所在的位置,performLayout()
- 是否需要重新绘制performDraw()
那么是什么导致View的重绘呢?这里总结了3个主要原因
- 视图本身内部状态(enable,pressed等)变化,可能引起重绘
- View内部添加或者删除了View
- View本身的大小和可见性发生了变化
View的绘制流程
在上一小节了,讲述了performTraversals()的是被WMS IPC调用执行的.View的绘制流程一般是
从performTraversals -> performMeasure() -> performLayout() -> performDraw().
下面看一下performMeasure()
- //ViewRootImpl
- private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
- if (mView == null) {
- return;
- }
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
- try {
- mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
- }
-
- public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
- MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY
- && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY;
- final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec)
- && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec);
- final boolean needsLayout = specChanged
- && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize);
- if (forceLayout || needsLayout) {
- mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
- resolveRtlPropertiesIfNeeded();
- int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
- if (cacheIndex < 0 || sIgnoreMeasureCache) {
- //在这里调用了onMeasure 方法
- onMeasure(widthMeasureSpec, heightMeasureSpec);
- mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
- }
- }
- }
最终调用了View的measure方法,而View中的measure()方法被定义成final类型,保证整个流程的执行.performLayout()和performDraw()也是类似的过程.
而对于程序员,自定义View只需要关注他提供出来几个对应的方法,onMeasure/onLayout/onDraw. 关于这方面知识的网上介绍的资料很多,也可以很容易的看到View及ViewGroup里面的代码,推荐看LinerLayout的源码理解这部分知识,在这里不详细展开.
Android的绘图原理浅析
Android屏幕绘制
关于绘制,就要从performDraw()说起,我们来看一下这个流程到底是怎么绘制的.
- //ViewRootImpl
- //1
- private void performDraw() {
- try {
- draw(fullRedrawNeeded);
- } finally {
- mIsDrawing = false;
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
- }
-
- //2
- private void draw(boolean fullRedrawNeeded) {
- Surface surface = mSurface;
- if (!surface.isValid()) {
- return;
- }
-
- if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
- return;
- }
- }
-
- //3
- private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
- boolean scalingRequired, Rect dirty) {
- Canvas canvas = mSurface.lockCanvas(dirty);
- }
看代码执行流程,1—>2->3, 最终拿到了Java层的canvas,然后进行一系列绘制操作.而canvas是通过Suface.lockCanvas()得到的.
(编辑:晋中站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|