android draw ondraw(三)

76 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情

dispatchDraw

  1. dispatchDraw最后一段
// 由于child.draw 会调用parent的mGroupFlags设置一些参数,所以重新更新一下flags
//由于 mGroupFlags是protected类型的,又因为view和viewGroup都在同一包中,所以view中可以获取到mGroupFlags,并对其修改。
flags = mGroupFlags;

//view.draw会调用这个函数applyLegacyAnimation,这个函数可能会导致这里flags设置为FLAG_INVALIDATE_REQUIRED
if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
    invalidate(true);
}

//调用动画监听器
if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
        mLayoutAnimationController.isDone() && !more) {
    mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
    final Runnable end = new Runnable() {
       @Override
       public void run() {
       //通知animationListener
           notifyAnimationListener();
       }
    };
    post(end);
}

post

public boolean post(Runnable action) {
        .....
        return attachInfo.mHandler.post(action);
        .....

我们通过post的源码可以看出来post是通过handler机制发生的。 这个attachInfo是view里面的静态类,也就说同一个activity里面的view的attachInfo都是同一个。 attachInfo是在ViewRootImpl的构造函数里面创建的。

其中attachInfo.mHandler = new ViewRootImpl.ViewRootHandler()

post(Runnable) 是不会走handleMessage的(这里的post(end)就是这样),而是直接调用Runnable.run()方法,当然这会发生在Looper绑定的线程中。

draw(Canvas canvas, ViewGroup parent, long drawingTime) 这个函数也挺长的

  1. 第一段
//canvas.isHardwareAccelerated可以判断该canvas是否启用硬件加速
//默认支持硬件加速,硬件加速时这里的canvas是canvas的子类:DisplayListCanvas
final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated();
//当view没有deattch,开启了硬件加速,这会是true
boolean drawingWithRenderNode = mAttachInfo != null
        && mAttachInfo.mHardwareAccelerated
        && hardwareAcceleratedCanvas;
//是否执行了invalidate
boolean more = false;
硬件加速知识:

在硬件加速中,每一个view中保存着一个renderNode,由它代表当前view在硬件加速中的形象

每一种绘制操作由的DisplayListOp表示

view.updateDisplayListIfDirty方法会收集当前view所需的绘制内容,这个方法还会执行dispatchGetDisplayList()来调用子view的updateDisplayListIfDirty方法。

2.

Transformation transformToApply = null;
boolean concatMatrix = false;
//指示是否处于兼容模式
final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired;
    ..........
RenderNode renderNode = null;
Bitmap cache = null;
int layerType = getLayerType(); 
//启动了软件绘制
if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) {
     if (layerType != LAYER_TYPE_NONE) {
     //没有指定硬件绘制,那么就是软件绘制
         layerType = LAYER_TYPE_SOFTWARE;
         buildDrawingCache(true);
    }
    cache = getDrawingCache(true);
}

//硬件绘制
if (drawingWithRenderNode) {
    //更新displaylist,如果renderNode失效递归调用view,更新displaylist
    renderNode = updateDisplayListIfDirty();
    //renderNode有效
    if (!renderNode.isValid()) {
        renderNode = null;
        drawingWithRenderNode = false;
    }
}

     ..............
//drawingWithDrawingCache = cache != null && !drawingWithRenderNode;
if (!drawingWithDrawingCache) {//硬件绘制或者软件绘制的cache为空
    //硬件绘制
    if (drawingWithRenderNode) {
        mPrivateFlags &= ~PFLAG_DIRTY_MASK;
        ((DisplayListCanvas) canvas).drawRenderNode(renderNode);
    } else {
        // 软件绘制
        //PFLAG_SKIP_DRAW指示是否跳过当前帧的绘制
        if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
            //draw()方法里面是否绘制涉及到的判断和PFLAG_DIRTY_MASK有关
            mPrivateFlags &= ~PFLAG_DIRTY_MASK;
            //分发子view绘制
            dispatchDraw(canvas);
        } else {
        //绘制自己
            draw(canvas);
        }
    }
} else if (cache != null) {//软件绘制且存在cache
    mPrivateFlags &= ~PFLAG_DIRTY_MASK;
    if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) {
        Paint cachePaint = parent.mCachePaint;
        if (cachePaint == null) {
            cachePaint = new Paint();
            cachePaint.setDither(false);
            parent.mCachePaint = cachePaint;
        }
        cachePaint.setAlpha((int) (alpha * 255));
        //绘制缓存
        canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
    } else {
        int layerPaintAlpha = mLayerPaint.getAlpha();
        if (alpha < 1) {
            mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha));
        }
        canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint);
        if (alpha < 1) {
        //绘制缓存
            mLayerPaint.setAlpha(layerPaintAlpha);
        }
    }
}