當硬加速被啟用,Android架構利用一個新的繪製模式來把你的應用呈現到螢幕,這個模式利用了一個顯示列表.要完全理解顯示列表以及它如何影響你的應用,先要理解android如何在非硬加速下繪製View.下面的小節描述了軟加速的和硬加速的繪製models.
軟體繪製模式
在軟體繪製模式,view按以下兩步進行繪製:
1使整個View層級都變得無效
2繪製所有的View層級
任何時候一個應用需要更新部分UI時,它應在任何改變了內容的View上調用invalidate()(或它的任一變體),使介面無效的訊息在整個View層級中傳播以計算應被繪製的螢幕地區(髒地區).之後Android系統繪任View層級中所有與髒地區有交集的View. 不幸的是,這種繪製模式有兩個缺點:
第一,這個模式需要在每個繪製路徑中都執行很多代碼.比如,如果你的應用在一個button上調用了invalidate()並且這個button位於另一個view之上,即使這個View沒有變化,Android系統也會繪製這個View.
第二個問題是這個繪製模式可能隱藏你應用中的bug.因為Android系統會繪製與髒地區有交集的view們,那麼一個你改變了內容的view可能在沒有被調用invalidate()時也會被重繪了.當這種情況發生時,你只能依賴那個需要重繪的view來獲得正確的行為.但這個行為可能在你每次修改你的應用時都會改變.因此,在任何你修改了資料或狀態而影響到繪製代碼的時候,你總是應該在你的自訂view上調用invalidate().
註:Androidview們會在它們的屬性被改變時自動調用invalidate(),比如一個TextView的背景和文本改變時.
硬加速繪製模式
Android系統依然使用invalidate()和draw()來請求螢幕更新並畫出views,但是對實際的繪製處理卻不一樣.現在不是在收到繪製命令立即執行了,而是Android系統把繪製命令記錄到顯示列表中,這個列表中包含了View層級的繪製代碼的輸出.另一個最佳化是Android系統只需為那些通過invalidate()標記為髒的View記錄和更新顯示列表.沒有被invalidated的Views可以簡單地使用先前的顯示列表中的記錄進行重繪.新的繪製模式包含三個階段:
1使整個View層級都無效
2記錄並更新顯示列表
3畫顯示列表
使用此模式,你再不能依靠讓View與髒地區交界而使它的draw()方法被調用.要保證Android系統記錄下view的顯示列表,你必須調用invalidate().忘記這樣做會導致一個view總是一個模樣,即使改變了它.但這是一個很容易被找出的bug.
使用顯示列表還對提升動畫效能有益,因為設定了某個屬性,比如alpha或rotation等,不再需invalidating目標view(自動做了).這個最佳化也會應用到擁有顯示列表的view上(當你的應用被硬加速時的任何view).例如,假設有一個LinearLayout包含了一個ListView和一個Button,ListView位於Button之上,LinearLayout的顯示列表看起來如下:
假設現在你想改變ListView的opacity,在調用了ListView的setAlpha(0.5f)後,顯示列表現在包含如下項:
ListView複雜的繪製過程沒有被執行,而是僅更新了更簡單的LinearLayout的顯示列表.如果在一個未硬加速的應用中,列表和它爹的繪製代碼都會被重新執行.
不支援的繪製操作
當啟用了硬加速,2D呈現管道會支援通用的Canvas繪製操作,也支援不常用的操作.所有的繪製操作被用來呈現widgets,layouts以及通用進階視覺效果,比如反光和平鋪紋理.下面的列表描述了已知的不能被硬加速支援的繪製操作:
Canvas
clipPath()
clipRegion()
drawPicture()
drawPosText()
drawTextOnPath()
drawVertices()
Paint
setLinearText()
setMaskFilter()
setRasterizer()
另外,還有一些操作的行為在啟用硬加速後會變得不一樣:
Canvas
Paint
setDither():被忽略
setFilterBitmap():濾鏡一直啟用
setShadowLayer():僅對文本起作用
ComposeShader
如果你的應用被這些缺少的特性或限制影響了,你可以通過調用setLayerType(View.LAYER_TYPE_SOFTWARE,null)為受影響的部分關閉硬加速.用此方法,你依然可以在其它地方享用到硬加速.