1. 程式人生 > >雙緩衝繪圖與SurfaceView(一):雙緩衝繪圖

雙緩衝繪圖與SurfaceView(一):雙緩衝繪圖

前言

為了方便後面描述,首先需要明確:每個canvas都持有一個bitmap,在canvas上進行的繪製操作(即呼叫canvas.drawXXX(...)),實際上都是在bitmap上進行繪製。

第一層緩衝

cpu訪問記憶體的速度要遠遠快於訪問螢幕的速度。如果我們需要在螢幕上繪製100個圖形,有兩種方案:第一種方案是每次從記憶體中讀取一個圖形然後將此圖形繪製到螢幕上,這樣的過程重複進行100次——因為需要訪問100次記憶體和100次螢幕,可想而知這種方案是非常耗時的;第二種方案是每次從記憶體中讀取一個圖形並繪製到記憶體中的一個臨時bitmap上,重複進行100次,然後再一次性將記憶體中繪製好的臨時bitmap繪製到螢幕上——顯然,這種方案可以節約大量的時間,因為只需要訪問一次螢幕。這第二種方案就是雙緩衝繪圖中的第一層緩衝。

android系統View類的onDraw方法中已經實現了這第一層緩衝,這從我們以往的開發經驗中就很容易發現:在對onDraw提供的canvas進行繪製時,並不是繪製一點就顯示一點,而是onDraw方法中的繪製工作全部完成後,才一次性將繪製的全部內容顯示到螢幕上。這裡的canvas中的bitmap就相當於前面所說的“記憶體中的臨時bitmap”。

第二層緩衝

要解決的問題

通常情況下,在自定義View中,所有的繪圖工作都是在UI執行緒中進行的(onDraw(…)方法運行於UI執行緒)。如果要繪製的影象非常複雜,耗時較多,並且需要頻繁繪製的話,那將會造成UI執行緒的長時間阻塞。結果是,系統無法及時對使用者的點選、觸控等事件做出響應(系統處理點選、觸控等事件都是在UI執行緒中進行的),會嚴重影響使用者體驗。

第二層緩衝

以繪製一個含有10000個圖形(如圓形、矩形、線條等)的複雜影象為例,第二層緩衝指的是:並不直接在onDraw方法的canvas中繪製這10000個圖形,而是(1)先將這10000個圖形繪製到一個臨時的canvas中,繪製完成之後,(2)再將此臨時canvas中的內容(也就是一個bitmap),通過canvas.drawBitmap繪製到onDraw方法的canvas中。

第二層緩衝的主要作用是可以減少繪圖工作對UI執行緒的阻塞,其利用的原理就是上面的操作(2)要快於操作(1)(因為操作(2)相當於就是簡單的bitmap拷貝)。

具體做法

我們可以建立一個臨時canvas,稱為tempCanvas,如下圖所示:

先在一個子執行緒中將10000個圖形繪製到tempBitmap中,然後呼叫postInvalidate觸發onDraw方法,在onDraw方法中(UI執行緒),將tempBitmap繪製到onDraw方法中的canvas中。因為在UI執行緒進行的工作只是簡單的bitmap拷貝,因此此舉能大大減少繪圖工作對UI執行緒的阻塞。這其實也是SurfaceView減少UI執行緒阻塞的原理。

//建立臨時的canvas並繪製
tempBitmap = Bitmap.createBitmap((int) width, (int) height, Bitmap.Config.RGB_565);
Canvas tempCavas = new Canvas(cacheBitmap);
tempCavas.drawXXX(...);
tempCavas.drawXXX(...);
...

@Override
protected void onDraw(Canvas canvas) {
    ...
    canvas.drawBitmap(tempBitmap, 0, 0, null);
    ...
}

第二層緩衝能減少繪圖工作對UI執行緒的阻塞,但不一定能提升通過頻繁繪製來實現的動畫的流暢度。分為兩種情形:

1.如果每一幀需要繪製的影象都不同,則繪製每一幀都需要執行操作(1)和操作(2),那麼動畫將更為卡頓。因為:首先,繪製一幀影象所需的時間 = 子執行緒中的繪製時間 + UI執行緒中的繪製時間,比不使用第二層緩衝時耗時更多;第二,在子執行緒和UI執行緒中都要用到tempBitmap,一個寫入,一個讀取,寫入和讀取不能並行,這就意味著,當在子執行緒中繪製完第n幀,並將tempBitmap交給UI執行緒之後,子執行緒並不能立即開始繪製第下一幀,因為tempBitmap此時被UI執行緒佔用了,必須等到UI執行緒中的繪製工作完成之後,子執行緒才能在tempBitmap上繼續繪製下一幀——也就是說,每一幀的繪製工作相當於是排隊進行的,無法並行。綜合以上兩點,總的結果就是,單位時間內可以繪製的幀數比不使用雙緩衝時更少了。

2.如果動畫每一幀需要繪製圖像都一樣(即只是簡單的整體位移、縮放等效果),或者動畫每一幀需要繪製的影象只是有區域性的細微差別,那麼通過對tempBitmap的複用,或者只是對tempBitmap進行區域性重繪,就可以大大縮短操作(1)的耗時。在這種情況下,使用第二層緩衝會使得動畫更為流暢。

相關推薦

緩衝繪圖SurfaceView()緩衝繪圖

前言 為了方便後面描述,首先需要明確:每個canvas都持有一個bitmap,在canvas上進行的繪製操作(即呼叫canvas.drawXXX(...)),實際上都是在bitmap上進行繪製。 第一層緩衝 cpu訪問記憶體的速度要遠遠快於訪問螢幕的速

numpyMatplotlib基本視窗介面

matploblib基本介面設定 matploblib基本介面設定 視窗操作 矩陣式佈局 柵格佈局 自由佈局 刻度定位器及座標系 刻度定位器: 刻度網格線

資料結構實驗之棧佇列進位制轉換(SDUT 2131)

題目連結 題解: 特判一下n==0的時候。 #include <bits/stdc++.h> using namespace std; int a[1000]; int main() {

資料結構實驗之棧佇列進位制轉換

Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Problem Description 輸入一個十進位制非負整數,將其轉換成對應的 R (2 <= R <= 9) 進位制數,並

[OJ.2131]資料結構實驗之棧佇列進位制轉換

                                   資料結構實驗之棧與佇列一:進位制轉換                                            Time Limit: 1000 ms                     

Gradle理論實踐Gradle入門

文章目錄 Gradle入門 1、配置Gradle環境 2、Gradle之Hello World 3、gradle 與gradlew的區別 4、Gradle命令介紹 5、Gradle 工作流程

MongoDB的學習應用安裝並簡單測試MongoDB

Document DatabaseA record in MongoDB is a document, which is a data structure composed of field and value pairs. MongoDB documents are similar to JSON obje

C#反射特性()反射基礎

目錄 C#反射與特性(一):反射基礎 1. 說明 1.1 關於反射、特性 2. 程式集操作 2.1 獲取 程式集物件(Assembly) 2.2 Assemb

思路實現個人如何獨立完成端App

作為一名獨立開發者,經常需要掌握各方面的技術與方法,無論是構思還是設計還是開發,都需要自己一個人去完成。 這時候,利用一些省力高效的訣竅便可以事半功倍,下面小編就來和大家分享一下小編的作品《跑車之家》的開發過程。 【靈感篇】 小編是名汽車迷,尤其是效能車、跑車迷,突

模擬色球彩票開獎結果隨機生成色球彩票.......

tint ack 模擬雙色球 test nbsp next 2-2 彩票 返回 模擬雙色球彩票開獎結果:隨機生成一註雙色球彩票,判斷其是否中獎,獎金為多少。一註雙色球彩票由6個不重復的紅球(序號:1~32)和1個籃球(序號:1~16)構成。雙色球中獎規則如下: (提示:①

Python數據類型端隊列deque-比列表list性能更高的種數據類型

mov 有趣 公眾 ons 數據類型 時間復雜度 可選參數 重要 增加 Python數據類型:雙端隊列 說到容器類型,大家第一時間想到的多半是list,而list確實也能解決大部分的需要,但碰到列表內的數據量相當大的時候,性能問題就顯得尤為重要;再或者列表被惡意註入一個無窮

Pandas繪圖(三)Plot()座標

pandas的畫圖功能還是挺全的,先看看雙座標的畫法,用到的關鍵函式是secondary_y,現在有一個1000*2的df,分BC兩列,用df3.B.plot()先畫B列,然後把C加進去通過secondary_y設定副座標,寫成一起的話連定義X座標就是ax=df3.plot(

css佈局飛翼佈局聖盃佈局

今天開班級會議,主要是講講畢業的事宜,其中一位同學說到他現在在專研一些新技術,但是我不建議他這麼做,畢竟基礎很重要程式設計主要學習的是思想 正題吧,前陣子朋友面試,有這麼一個要求: 就是兩邊定寬,中間自適應的三欄佈局 是不是感覺很簡單,但是我事後試了試,發現不是那麼簡單,

Android圖形系統的分析移植--七、緩衝framebuffer的實現

1  實現原理在基本的FrameBuffer已經實現的基礎上,需要實現的是與Android原本模擬器所使用的goldfish FrameBuffer之間的區別。比較一下不難發現,從以下及方面著手:1.                  修改初始化FrameBuffer資訊;2

PictureBox空間繫結類,通過函式控制顯示重新整理,開啟緩衝

巧用GDI32.Dll做控制元件繫結 與 影象重新整理 開啟雙緩衝,如下程式碼所示 SetStyle( ControlStyles.OptimizedDoubleBuffer | Con

模擬色球彩票開獎結果隨機生成色球彩票,判斷其是否中獎,獎金為多少。

利用random類隨機生成1-32六個不相同的數值作為雙色球號碼的紅球, 再生成一個1-16隨機數作為藍球的號碼。將此存放到陣列中。 同理生成一箇中獎號碼,兩個陣列進行比較,當有相同的數時進行計數。最後可以通過計數值知道自己中了幾等獎。 package t

Delphi中在TForm繪圖時使用DoubleBuffered實現緩衝的副作用

在使用TForm的DoubleBuffered屬性實現雙緩衝時,如果TForm中同時包含了TToolBar控制元件,在執行時TToolBar控制元件可能變黑,這應該是Delphi的一個bug;所以這個時候建立一個panel,然戶在panel上放置paintbox進行繪圖,使

Keepalived案例Keepalived機熱備(HA)精講

這裡我們僅僅只利用Keepalive做雙機熱備,也就是保證伺服器的高可用性,其他的不用管。可能您會說這樣在實際應用中很少會這樣用,這您可就錯了,Keepalived僅僅做雙機熱備的情況還是有的,我就碰到過幾次這樣的案例,下面就我碰到的幾個案例做個小結一,Keepalived

資料結構演算法—文多圖搞懂鏈表

前言 前面講過線性表中順序表和連結串列的實現和性質。但是在資料結構與演算法中,雙向連結串列無論在考察還是運用中都佔有很大的比例,筆者旨在通過本文與讀者一起學習分享雙鏈表相關知識。   雙鏈表介紹 與單鏈表區別 邏輯上沒有區別。他們均是完成線性表的內容。主要的區別是結構上的構造有所區別。 

odoo12之應用因子驗證(Two-factor authentication, 2FA)(HOTP,TOTP)附原始碼

前言       雙因子認證:雙因子認證(2FA)是指結合密碼以及實物(信用卡、SMS手機、令牌或指紋等生物標誌)兩種條件對使用者進行認證的方法。--百度百科       跟我一樣"老"的網癮少年想必一定見過買點卡後上面送的密保(類似但不完全一樣