敢問Canvas來自何方

Canvas的故事

來自一個群友的問題:

使用Canvas繪制的時候坐標(biāo)系是什么落午?是屏幕坐標(biāo)系還是view坐標(biāo)系穿撮?

Canvas是單例嗎沈矿?

樂于助(shui)人(qun)的我說了一句… “翻看源碼看看onDraw是怎么被調(diào)用的”移斩,然后我也沒有管住我這個手…

其實我們做的事情很簡單 - 就是:分析onDraw的方法調(diào)用棧

代碼環(huán)節(jié)

onDraw -> draw

然后我們看draw

AS代碼分析

這幾個方法我們挨個瞅瞅(這就是靜態(tài)代碼分析的蛋疼之處肚医,一個函數(shù)被多處調(diào)用的時候,要挨個檢查向瓷,一會我會說一個更方便的方法)

最后我們追查到ViewupdateDisplayListIfDirty方法

省略掉其他代碼肠套,我們可以看到Canvas被創(chuàng)建

/**
     * 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一個。如果成功取得朱躺,那就調(diào)用一個方法來把這個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不是全局單例,而是在一個池里緩存著巢钓。

碎碎念

另外一種分析代碼的方法… 我叫做“動態(tài)分析法”病苗,就是在代碼運行的時候打斷點,然后查看斷點時的函數(shù)調(diào)用棧症汹,通過Debug信息里面的調(diào)用棧來查看onDraw里面的Canvas是從哪里來的硫朦。

可以看另一篇博客,它就是動態(tài)分析來看這個Canvas背镇,寫的也很nice

Canvas坐標(biāo)系

onDraw里面的坐標(biāo)系是View坐標(biāo)系而不是屏幕坐標(biāo)系咬展。

為什么泽裳?canvas在創(chuàng)建的時候并不知道view在哪里也不懂view坐標(biāo)系,它只是一個畫布破婆。是Android系統(tǒng)幫你悄悄地做了Translate操作涮总。

(這部分代碼解析最近會更)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市祷舀,隨后出現(xiàn)的幾起案子瀑梗,更是在濱河造成了極大的恐慌,老刑警劉巖裳扯,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抛丽,死亡現(xiàn)場離奇詭異,居然都是意外死亡饰豺,警方通過查閱死者的電腦和手機亿鲜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哟忍,“玉大人狡门,你說我怎么就攤上這事」埽” “怎么了其馏?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長爆安。 經(jīng)常有香客問我叛复,道長,這世上最難降的妖魔是什么扔仓? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任褐奥,我火速辦了婚禮,結(jié)果婚禮上翘簇,老公的妹妹穿的比我還像新娘撬码。我一直安慰自己,他們只是感情好版保,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布呜笑。 她就那樣靜靜地躺著,像睡著了一般彻犁。 火紅的嫁衣襯著肌膚如雪叫胁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天汞幢,我揣著相機與錄音驼鹅,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛输钩,可吹牛的內(nèi)容都是我干的豺型。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼买乃,長吁一口氣:“原來是場噩夢啊……” “哼触创!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起为牍,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎岩馍,沒想到半個月后碉咆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡蛀恩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年疫铜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片双谆。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡壳咕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出顽馋,到底是詐尸還是另有隱情谓厘,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布寸谜,位于F島的核電站竟稳,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏熊痴。R本人自食惡果不足惜他爸,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望果善。 院中可真熱鬧诊笤,春花似錦、人聲如沸巾陕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惜论。三九已至许赃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間馆类,已是汗流浹背混聊。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人句喜。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓预愤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親咳胃。 傳聞我的和親對象是個殘疾皇子植康,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容