Android View 繪制流程 簡述 (無限遞歸+BitMap問題)

繪制流程

在 Android?的 View 系統中,draw(canvas)?和?dispatchDraw(canvas)?是繪制流程中的兩個關鍵方法:

1.?draw(canvas)?方法的作用

draw(canvas)?是?View 類中的核心繪制方法,它的主要職責包括:

  1. 繪制背景?- 調用?drawBackground(canvas)
  1. 保存畫布狀態?- 調用?canvas.save()
  1. 繪制內容?- 調用?onDraw(canvas)
  1. 繪制子視圖?- 調用?dispatchDraw(canvas)
  1. 繪制前景?- 調用?onDrawForeground(canvas)
  1. 恢復畫布狀態?- 調用?canvas.restore()

2.?dispatchDraw(canvas)?的作用

dispatchDraw(canvas)?專門負責繪制子視圖,它的調用鏈是:

===========================================

draw(canvas)?
? ↓
dispatchDraw(canvas) ?← 在這里被調用
? ↓
onDraw(canvas) ?← 子視圖的繪制

===========================================

無限遞歸的問題示例

自定義View 的部分代碼:

override fun dispatchDraw(canvas: Canvas) {// 繪制矩形// ...// 調用父類的 dispatchDraw 來繪制子視圖super.dispatchDraw(canvas)// 縮略圖回調post { generateThumbnail() }
}private fun generateThumbnail() {try {// 創建縮略圖val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)val canvas = Canvas(bitmap)// 這里調用 draw(canvas) 會導致問題draw(canvas)// ← 這里會再次觸發 dispatchDraw!val thumbnail = Bitmap.createScaledBitmap(bitmap, 120, 80, true)thumbnailCallback?.onThumbnailUpdated(thumbnail)} catch (e: Exception) {Log.e(TAG, "Error generating thumbnail", e)}
}

4. 無限遞歸的原因

當你調用?draw(canvas)?時:

  1. ?draw(canvas)?被調用
  2. draw(canvas)?內部調用?dispatchDraw(canvas)
  3. dispatchDraw(canvas)?被調用
  4. dispatchDraw(canvas)?內部調用?generateThumbnail()
  5. generateThumbnail()?內部調用?draw(canvas)
  6. 回到步驟 1,形成無限循環

5. 解決方案

這就是為什么我們修改了?generateThumbnail()?方法,直接繪制矩形而不調用?draw(canvas)

private fun generateThumbnail() {// 直接繪制矩形,避免調用 draw()for (rect in rects) {paint.color = rect.colorval left = rect.cx - rect.width / 2val top = rect.cy - rect.height / 2val right = rect.cx + rect.width / 2val bottom = rect.cy + rect.height / 2canvas.drawRect(left, top, right, bottom, paint)}
}

總結

draw(canvas)?調用?dispatchDraw(canvas)?是 Android View?系統的標準繪制流程,這是為了確保:

  1. 父視圖先繪制自己的內容
  1. 然后繪制所有子視圖
  1. 最后繪制前景

當你在?dispatchDraw()?中調用?draw()?時,就會打破這個流程,導致無限遞歸。正確的做法是直接操作 Canvas?進行繪制,而不是調用 View 的?draw()?方法。

bitMap問題

    /*** 生成縮略圖*/private fun generateThumbnail() {try {// 創建縮略圖大小的 Bitmapval thumbnailWidth = 120val thumbnailHeight = 80val bitmap = Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888)val canvas = Canvas(bitmap)//            // 設置白色背景
//            canvas.drawColor(Color.WHITE)// 計算縮放比例val scaleX = thumbnailWidth.toFloat() / widthval scaleY = thumbnailHeight.toFloat() / heightval scale = minOf(scaleX, scaleY)// 計算居中偏移val offsetX = (thumbnailWidth - width * scale) / 2val offsetY = (thumbnailHeight - height * scale) / 2// 應用變換canvas.save()canvas.translate(offsetX, offsetY)canvas.scale(scale, scale)// 應用當前視圖的變換(平移和縮放)val cx = width / 2fval cy = height / 2fcanvas.translate(this.offsetX, this.offsetY)canvas.scale(scaleFactor, scaleFactor, cx, cy)// 直接繪制矩形,避免調用 draw()for (rect in rects) {paint.color = rect.colorval left = rect.cx - rect.width / 2val top = rect.cy - rect.height / 2val right = rect.cx + rect.width / 2val bottom = rect.cy + rect.height / 2canvas.drawRect(left, top, right, bottom, paint)}canvas.restore()thumbnailCallback?.onThumbnailUpdated(bitmap)} catch (e: Exception) {Log.e(TAG, "Error generating thumbnail", e)}}

?內存消耗的巨大差異

之前的實現(大?Bitmap):

  • 假設屏幕尺寸:1080×1920 像素
  • Bitmap 大小:1080 × 1920 ×?4 bytes?=?8.3MB
  • 每次生成縮略圖都需要?8.3MB 內存
  • 頻繁創建和銷毀大 Bitmap

現在的實現(小 Bitmap):

  • 縮略圖尺寸:120×80 像素
  • Bitmap 大小:120 ×?80?× 4 bytes?=?38.4KB
  • 內存使用量減少了?99.5%

問題總結

1.?無限遞歸 + 大 Bitmap 的雙重打擊

之前的實現存在兩個致命問題:

  1. 無限遞歸:draw(canvas)?→?dispatchDraw(canvas)?→?generateThumbnail()?→?draw(canvas)
  1. 大 Bitmap?創建:每次遞歸都創建?8.3MB 的 Bitmap

這導致:

  • CPU?使用率 100%
  • 內存快速耗盡(每秒可能創建幾十個 8.3MB 的 Bitmap)
  • 應用崩潰或重啟

2.?Bitmap 縮放的開銷

之前的實現還需要額外的縮放操作:

kotlin

Apply to DeepLearnVie...

//?額外的縮放操作

val?scaledBitmap?=?Bitmap.createScaledBitmap(bitmap,?120,?80,?true)

這個操作本身就很耗?CPU 和內存。

3.?頻繁的垃圾回收

大 Bitmap 的頻繁創建和銷毀會觸發:

  • 頻繁的垃圾回收
  • 內存碎片化
  • 系統卡頓

再進一步優化:?

Android View 繪制流程 優化 (Bitmap 復用+內容變化檢測+防抖調度策略)-CSDN博客

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/914347.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/914347.shtml
英文地址,請注明出處:http://en.pswp.cn/news/914347.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

算法學習筆記:18.拉斯維加斯算法 ——從原理到實戰,涵蓋 LeetCode 與考研 408 例題

在隨機化算法領域,拉斯維加斯(Las Vegas)算法以其獨特的設計思想占據重要地位。與蒙特卡洛(Monte Carlo)算法不同,拉斯維加斯算法總能給出正確的結果,但運行時間具有隨機性 —— 在最壞情況下可…

26-計組-指令執行過程

一、指令周期1. 定義與組成定義:CPU取出并執行一條指令所需的全部時間,稱為指令周期。子周期劃分:取指周期(必選):從存儲器取指令到指令寄存器(IR)。間址周期(可選&#…

【JMeter】數據驅動測試

文章目錄創建數據文件加載數據文件根據數據文件請求接口、傳遞參數拓展含義:根據數據的數量、內容,自動的決定用例的數據和內容。數據驅動測試用例。步驟: 創建數據文件加載數據文件根據數據文件請求接口、傳遞參數 創建數據文件 Jmeter支…

Springboot實現一個接口加密

首先來看效果這個主要是為了防止篡改請求的。 我們這里采用的是一個AOP的攔截,在有需要這樣的接口上添加了加密處理。 下面是一些功能防篡改HMAC-SHA256 參數簽名密鑰僅客戶端 & 服務器持有防重放秒級時間戳 有效窗口校驗默認允許 5 分鐘防竊聽AES/CBC/PKCS5Pa…

斯坦福 CS336 動手大語言模型 Assignment1 BPE Tokenizer TransformerLM

所有代碼更新至 https://github.com/WangYuHang-cmd/CS336/tree/main/assignment1-basics 作業文件結構: CS336/assignment1-basics/ ├── tests/ # 測試文件目錄 │ ├── adapters.py # 適配器測試 │ ├── conftest.py # pyt…

Spring Cloud Gateway 實戰指南

關鍵詞:微服務、API網關、Spring Cloud Gateway、路由轉發、限流熔斷 ? 文章摘要 隨著互聯網應用規模的不斷擴大,傳統的單體架構逐漸向微服務架構轉型。在微服務架構中,API 網關作為系統的入口點,承擔了諸如請求路由、負載均衡、…

PyTorch自動微分:從基礎到實戰

目錄 1. 自動微分是什么? 1.1 計算圖 1.2 requires_grad 屬性 2. 標量和向量的梯度計算 2.1 標量梯度 2.2 向量梯度 3. 梯度上下文控制 3.1 禁用梯度計算 3.2 累計梯度 4. 梯度下降實戰 4.1 求函數最小值 4.2 線性回歸參數求解 5. 總結 在深度學習中&a…

Spring AI 項目實戰(十六):Spring Boot + AI + 通義萬相圖像生成工具全棧項目實戰(附完整源碼)

系列文章 序號文章名稱1Spring AI 項目實戰(一):Spring AI 核心模塊入門2Spring AI 項目實戰(二):Spring Boot + AI + DeepSeek 深度實戰(附完整源碼)3Spring AI 項目實戰(三):Spring Boot + AI + DeepSeek 打造智能客服系統(附完整源碼)4

從零到一:企業如何組建安全團隊

在這個"黑客滿天飛,漏洞遍地跑"的時代,沒有安全團隊的企業就像裸奔的勇士——雖然很有勇氣,但結局往往很悲慘。 📋 目錄 為什么要組建安全團隊安全團隊的核心職能團隊架構設計人員配置策略技術體系建設制度流程建立實施…

業務訪問控制-ACL與包過濾

業務訪問控制-ACL與包過濾 ACL的定義及應用場景ACL(Access Control List,訪問控制列表)是用來實現數據包識別功能的;ACL可以應用于諸多場景: 包過濾功能:對數據包進行放通或過濾操作。NAT(Netwo…

穿梭時空的智慧向導:Deepoc具身智能如何賦予導覽機器人“人情味”

穿梭時空的智慧向導:Deepoc具身智能如何賦予導覽機器人“人情味”清晨,當第一縷陽光透過高大的彩繪玻璃窗,灑在博物館光潔的地板上,一位特別的“館員”已悄然“蘇醒”。它沒有制服,卻有著清晰的指引;它無需…

PostgreSQL 查詢庫中所有表占用磁盤大小、表大小

SELECTn.nspname AS schema_name,c.relname AS table_name,-- 1?? 總大小(表 toast 索引)pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size,-- 2?? 表不包含索引(含 TOAST)pg_size_pretty(pg_total_relation_s…

日記-生活隨想

最近鼠鼠也是來到上海打拼(實習)了,那么秉持著來都來了的原則,鼠鼠也是去bw逛了逛,雖說沒票只能在外場看看😭。可惜幾乎沒有多少我非常喜歡的ip,不由感慨現在的二次元圈已經變樣了。雖說我知道內…

串口A和S的含義以及RT的含義

A async 異步S sync 同步RT 收發U A RT 異步U SA RT 同步/異步

spring cloud負載均衡分析之FeignBlockingLoadBalancerClient、BlockingLoadBalancerClient

本文主要分析被 FeignClient 注解的接口類請求過程中負載均衡邏輯&#xff0c;流程分析使用的依賴版本信息如下&#xff1a;<spring-boot.version>3.2.1</spring-boot.version><spring-cloud.version>2023.0.0</spring-cloud.version><com.alibaba.…

ref 和 reactive

文章目錄ref 和 reactive一、差異二、能否替代的場景分析&#xff08;1&#xff09;基本類型數據&#xff08;2&#xff09;對象類型數據&#xff08;3&#xff09;數組類型數據&#xff08;4&#xff09; 需要整體替換的場景三、替代方案與兼容寫法1. 用 reactive 模擬 ref2. …

BatchNorm 與 LayerNorm:原理、實現與應用對比

BatchNorm 與 LayerNorm&#xff1a;原理、實現與應用對比 Batch Normalization (批歸一化) 和 Layer Normalization (層歸一化) 是深度學習中兩種核心的歸一化技術&#xff0c;它們解決了神經網絡訓練中的內部協變量偏移問題&#xff0c;大幅提升了模型訓練的穩定性和收斂速度…

OcsNG基于debian一鍵部署腳本

&#x1f914; 為什么有了GLPI還要部署OCS-NG&#xff1f; 核心問題&#xff1a;數據收集的風險 GLPI直接收集的問題&#xff1a; Agent直接向GLPI報告數據時&#xff0c;任何收集異常都會直接影響資產數據庫網絡問題、Agent故障可能導致重復資產、錯誤數據、資產丟失無法對收集…

001_Claude開發者指南介紹

Claude開發者指南介紹 目錄 Claude簡介Claude 4 模型開始使用核心功能支持資源 Claude簡介 Claude 是由 Anthropic 構建的高性能、可信賴和智能的 AI 平臺。Claude 具備出色的語言、推理、分析和編程能力&#xff0c;可以幫助您解決各種復雜任務。 想要與 Claude 聊天嗎&a…

004_Claude功能特性與API使用

Claude功能特性與API使用 目錄 API 基礎使用核心功能特性高級功能開發工具平臺支持 API 基礎使用 快速開始 通過 Anthropic Console 獲取 API 訪問權限&#xff1a; 在 console.anthropic.com/account/keys 生成 API 密鑰使用 Workbench 在瀏覽器中測試 API 認證方式 H…