美文网首页
敢问Canvas来自何方

敢问Canvas来自何方

作者: RetroX | 来源:发表于2018-03-01 21:20 被阅读116次

Canvas的故事

来自一个群友的问题:

使用Canvas绘制的时候坐标系是什么?是屏幕坐标系还是view坐标系?

Canvas是单例吗?

乐于助(shui)人(qun)的我说了一句… “翻看源码看看onDraw是怎么被调用的”,然后我也没有管住我这个手…

其实我们做的事情很简单 - 就是:分析onDraw的方法调用栈

代码环节

onDraw -> draw

然后我们看draw

AS代码分析

这几个方法我们挨个瞅瞅(这就是静态代码分析的蛋疼之处,一个函数被多处调用的时候,要挨个检查,一会我会说一个更方便的方法)

最后我们追查到ViewupdateDisplayListIfDirty方法

省略掉其他代码,我们可以看到Canvas被创建

/**
     * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported)
     * @hide
     */
    @NonNull
    public RenderNode updateDisplayListIfDirty() {
        final RenderNode renderNode = mRenderNode;
        // 省略大量代码
            int width = mRight - mLeft;
            int height = mBottom - mTop;
            int layerType = getLayerType();

            final DisplayListCanvas canvas = renderNode.start(width, height);
            canvas.setHighContrastText(mAttachInfo.mHighContrastText);

            try {
                // 省略大量代码
                        draw(canvas);
                    
                }
            } finally {
                renderNode.end(canvas);
                setDisplayListProperties(renderNode);
            }
        } else {
            mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
            mPrivateFlags &= ~PFLAG_DIRTY_MASK;
        }
        return renderNode;
    }
final DisplayListCanvas canvas = renderNode.start(width, height);
canvas.setHighContrastText(mAttachInfo.mHighContrastText);

然后我们看renderNode.start这个方法

public DisplayListCanvas start(int width, int height) {
        return DisplayListCanvas.obtain(this, width, height);
    }

然后到这个obtain方法

//DisplayListCanvas类的方法
static DisplayListCanvas obtain(@NonNull RenderNode node, int width, int height) {
        if (node == null) throw new IllegalArgumentException("node cannot be null");
        DisplayListCanvas canvas = sPool.acquire();
        if (canvas == null) {
            canvas = new DisplayListCanvas(node, width, height);
        } else {
            nResetDisplayListCanvas(canvas.mNativeCanvasWrapper, node.mNativeRenderNode,
                    width, height);
        }
        canvas.mNode = node;
        canvas.mWidth = width;
        canvas.mHeight = height;
        return canvas;
    }

在这里我们就可以看到,代码会先尝试从sPool取得一个Canvas,如果无法取得,那就自己new一个。如果成功取得,那就调用一个方法来把这个canvas给reset掉。

最后我们来看看这个sPool到底是啥东西

//DisplayListCanvas类的变量 
private static final int POOL_LIMIT = 25;
private static final SynchronizedPool<DisplayListCanvas> sPool =
         new SynchronizedPool<>(POOL_LIMIT);

//DisplayListCanvas类的方法
void recycle() {
        mNode = null;
        sPool.release(this);
    }

这里就很清楚了,在需要Canvas的时候,从这个容量25的池子里面取一个来用,取不出就只好自己new一个,在canvas完成工作后,回收到这个池子里面。

所以Canvas不是全局单例,而是在一个池里缓存着。

碎碎念

另外一种分析代码的方法… 我叫做“动态分析法”,就是在代码运行的时候打断点,然后查看断点时的函数调用栈,通过Debug信息里面的调用栈来查看onDraw里面的Canvas是从哪里来的。

可以看另一篇博客,它就是动态分析来看这个Canvas,写的也很nice

Canvas坐标系

onDraw里面的坐标系是View坐标系而不是屏幕坐标系。

为什么?canvas在创建的时候并不知道view在哪里也不懂view坐标系,它只是一个画布。是Android系统帮你悄悄地做了Translate操作。

(这部分代码解析最近会更)

相关文章

  • 敢问Canvas来自何方

    Canvas的故事 来自一个群友的问题:使用Canvas绘制的时候坐标系是什么?是屏幕坐标系还是view坐标系?C...

  • 敢问,尔来自何方

    沐浴山风,风走波纹, 水中游鱼像我,像我 从溪流上徒步溪流下。 马踏青草,沾满芳华, 草上虫儿像我,像我 从无草处...

  • 10-1定位

    【标题】敢问路在何方? 【字数】590 【正文】 敢问路在何方? 不敢问… 很多人不敢问自己的路到底在何方,方向是...

  • 敢问,路在何方?

    90秒都有不过去十字路口,灯火阑珊,如同白昼。放眼望去,霓虹闪烁,好不繁华。然而,哪一抹繁华真正属于你我的? 每天...

  • 敢问,路在何方

    自从用了网易云音乐软件,我渐渐养成了用音乐表达心情,很多时候听的不是歌,而是当下的一种心情,歌词、旋律都反...

  • 敢问,路在何方?

    浮生醉花前,偷得半日闲。金樽斗十千,往事多笑谈。但求故乡月,归来仍少年! ...

  • 敢问路在何方

    敢问路在何方,路在脚下。

  • 【曼陀罗028/100】前行

    敢问路在何方? 其实路就在脚下。

  • 请问: 路在何方?

    "敢问路在何方?” "路在脚下!” 这两句出自86版电视剧西游记主题曲和插曲《敢问路在何方》...

  • 「简书交友」姑娘在此,敢问朋友来自何方?

    骞,张骞出使西域的骞;予,给予的予。 搞笑的是经常会被人喊成“赛矛”或“赛予” 这就是我的名字。此名非实名但胜似实...

网友评论

      本文标题:敢问Canvas来自何方

      本文链接:https://www.haomeiwen.com/subject/uoinxftx.html