首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android View.invalidate() 觸發重繪原理與 Drawable.mutate() 狀態隔離機制深度解析

     編輯:程式設計綜合問答

一、invalidate() 如何觸發 draw()

調用鏈:
view.invalidate() → parent.invalidateChild() → ... → ViewRootImpl.scheduleTraversals() → Handler 發送 MSG_DO_TRAVERSAL → performTraversals() → draw() → onDraw()

關鍵點:ViewRootImpl 通過 Choreographer 與 VSync 對齊,合併同一幀內多次 invalidate,最終統一執行 performTraversals,保證每幀最多繪製一次。

二、Drawable.mutate() 為什麼能隔離狀態

默認共享機制

同一資源 ID 加載的 Drawable 實例共享同一 ConstantState(包含圖片像素、內在寬高、透明度等不可變數據),修改 alpha、colorFilter 等可變屬性時,**直接修改共享狀態**,導致所有引用處同步變化。

mutate() 做了什麼

public Drawable mutate() {
    if (!mutated && constantState != null) {
        constantState = constantState.newConstantState(); // 深拷貝 ConstantState
        mutated = true;
    }
    return this;
}
  • 首次調用:拷貝一份新的 ConstantState,後續屬性修改作用於副本,實現隔離。
  • 再次調用:mutated == true,直接返回自身,不再拷貝。

BitmapDrawable 特例

其 ConstantState 內持有 Bitmap 引用,**拷貝 ConstantState 並不複製 Bitmap 像素**,故內存開銷極小,僅隔離透明度、色調等繪製參數。

實戰建議

  1. 列表項、按鈕等復用場景,若需單獨調整圖標顏色/透明度,**務必先 mutate()**。
  2. 若需真正獨立像素(如裁剪、旋轉),請手動 bitmap.copy() 創建新 Bitmap。
  3. API 21+ 可用 DrawableCompat.wrap(drawable).mutate() 兼容舊版本。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved