雙緩沖、多緩沖技術(shù)在計算機(jī)科學(xué)中其實是一個廣義的概念狗准,不過其本質(zhì)上的意思都是差不多的剃浇。今天我們就來講一講雙緩沖技術(shù)在android繪圖中的應(yīng)用耘柱。
何謂緩沖?
在理解雙緩沖的原理之前同欠,我們先要明白样傍,什么叫緩沖?
我們可以舉一個比較通俗的粟子铺遂,比如:
工頭給你一個任務(wù)衫哥,讓你把50塊大板磚從A處搬到距離你1000米之外的B處去。你心想娃循,50塊板磚炕檩? 小case,我一次就能扛完。于是你擼起袖子捌斧,一步一步笛质,真的一趟就搞定了。這個時候工頭一聲奸笑對你說捞蚂,小伙子不錯妇押,那邊還有2000塊磚,你也搬過去吧姓迅。敲霍。俊马。
看到這堆積如山的磚頭,你眼前一黑肩杈,這孫子真是想累死我啊柴我,錢給這么少還干這么多活!
可是沒辦法呀扩然,誰叫自己當(dāng)初書讀得少艘儒,長大了只能靠搬磚為生呢。正當(dāng)你準(zhǔn)備徒手一趟一趟地開始干時夫偶,豐滿漂亮的工頭界睁,的老婆來了,她走過來兵拢,帶著迷一般的微笑翻斟。那種笑容,甜蜜優(yōu)雅说铃,仿佛春風(fēng)拂過瀘沽湖访惜,秋雨浸潤九寨溝,讓你虎軀一震腻扇。她對你說疾牲,你開工地上的卡車把這些磚搬過去吧,2000塊磚太多了衙解,一趟一趟搬太累阳柔。
你瞬間來了精神,把磚搬到卡車上蚓峦,油門一踩不帶走一片云彩舌剂,一下就把2000塊磚搬過去了。暑椰。霍转。
............
“快起來,什么時候了還在睡一汽,快去搬磚避消!”
該死的工頭又來催!
緩沖的概念就講到這里召夹。
Android繪圖中的雙緩沖
我們知道岩喷,我們在繪圖時有兩樣?xùn)|西是少不了的,一個是Canvas(畫布)监憎,一個是Paint(畫筆)纱意。Canvas提供畫各種圖形的方法,如畫圓(drawCircle)鲸阔,畫矩形(drawRect)等等偷霉,Paint用來設(shè)置畫筆的樣式迄委,比如筆的粗細(xì),顏色等类少。每個Canvas內(nèi)部持有一個Bitmap對象的引用叙身,畫圖的過程其實就是往這個Bitmap當(dāng)中寫入ARGB信息。
比如我們現(xiàn)在自定義一個View,在上面畫一個矩形和一個圓:
@Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(rect,mPaint);
canvas.drawCircle(cx,cy,100,mPaint);
}
那么現(xiàn)在有一個問題硫狞,畫矩形和畫圓是兩個獨立的動作曲梗,會不會在drawRect執(zhí)行完之后屏幕上馬上就會顯示出來一個矩形呢?
為了驗證我們的猜想妓忍,我們在兩個繪圖動作中加一個sleep:
@Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(rect,mPaint);
try {
TimeUnit.MILLISECONDS.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
canvas.drawCircle(cx,cy,100,mPaint);
}
我們會看到,并不是先顯示矩形再顯示圓愧旦,而是兩個幾乎同時一起顯示出來的世剖。這就說明必須要等onDraw方法執(zhí)行完成之后,才會把數(shù)據(jù)交給GPU去處理展示笤虫。這就是android繪圖當(dāng)中的第一道緩沖旁瘫,即顯示緩沖區(qū)。
而所謂的雙緩沖琼蚯,在android繪圖中其實就是再創(chuàng)建一個Canvas和對應(yīng)的Bitmap酬凳,然后在onDraw方法里默認(rèn)的Canvas通過drawBitmap畫剛才new的那個bitmap從而實現(xiàn)雙緩沖。用代碼簡單的表述是這樣的:
private void init(){
Bitmap bufferBm = Bitmap.create(getWidth,getHeight,Bitmap.Config.ARGB_8888);
Canvas bufferCanvas = new Canvas(bufferBm);
}
private void drawSomething(){
bufferCanvas.drawRect();
bufferCanvas.drawCircle();
...
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(bufferBm,0,0,null);
}
示意圖:
雙緩沖繪圖的優(yōu)缺點及適用場景
我們通過一個例子來說明遭庶。
實現(xiàn)這樣一個功能宁仔,一個自定義View,每次點擊的時候在點擊處畫一個圓。我們先不使用雙緩沖來實現(xiàn):
不用雙緩沖的代碼:
public class MyView extends View{
private Paint mPaint;
private List<Point> mPoints;
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.GREEN);
setBackgroundColor(Color.WHITE);
mPoints = new ArrayList<>();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
mPoints.add(new Point((int)event.getX(),(int)event.getY()));
break;
case MotionEvent.ACTION_UP:
invalidate();
break;
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
for (Point p : mPoints) {
canvas.drawCircle(p.x,p.y,50,mPaint);
}
}
在實驗之前峦睡,我們先打開開發(fā)者選項里的”GPU呈現(xiàn)模式分析“翎苫,設(shè)置為“在屏幕上顯示為條形圖”(不同的手機(jī)可能有略微的差異,我這里用的是google Nexus5)榨了。
可以看到煎谍,當(dāng)畫的圓數(shù)目比較少時,GPU的負(fù)荷較低龙屉,但是出現(xiàn)一個逐步上升的趨勢:
內(nèi)存使用情況是這樣的:
當(dāng)畫的圓數(shù)目增加到比較大時呐粘,GPU負(fù)荷有點慘不妨睹了:
這時的內(nèi)存使用情況:
我們現(xiàn)在改用雙緩沖來繪圖,代碼如下:
public class MyView extends View{
private Paint mPaint;
private Canvas mBufferCanvas;
private Bitmap mBufferBitmap;
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.GREEN);
setBackgroundColor(Color.WHITE);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
if (mBufferBitmap == null) {
mBufferBitmap = Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888);
mBufferCanvas = new Canvas(mBufferBitmap);
}
mBufferCanvas.drawCircle((int)event.getX(),(int)event.getY(),50,mPaint);
break;
case MotionEvent.ACTION_UP:
invalidate();
break;
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
if (mBufferBitmap == null) {
return;
}
canvas.drawBitmap(mBufferBitmap,0,0,null);
}
}
使用雙緩沖转捕,在數(shù)量較小時的GPU使用情況是這樣的:
這時候的內(nèi)存使用情況:
使用雙緩沖作岖,在數(shù)量非常大的時候,GPU使用情況是這樣的:
內(nèi)存使用情況:
從上面的實驗數(shù)據(jù)我們可以得出結(jié)論:
- 在繪制數(shù)據(jù)量較小時五芝,不使用雙緩沖鳍咱,GPU的負(fù)荷更低,即繪制性能更高与柑;
- 在繪制數(shù)據(jù)量較大時谤辜,使用雙緩沖繪圖蓄坏,繪制性能明顯高于不使用雙緩沖的情況;
- 使用雙緩沖會增加內(nèi)存消耗丑念。
其實上面的結(jié)論也很好理解涡戳,就像上面舉的搬磚的例子,如果磚少的話脯倚,用車來拉明顯是劃不來的渔彰,磚的數(shù)量很多的時候,用車來拉就可以節(jié)省很多時間推正,但是用車就要消耗額外的資源恍涂,這就需要根據(jù)不同的情況做出正確的選擇。
android的雙緩沖繪圖技術(shù)就講到這里植榕,有不對的地方或大家有什么問題歡迎留言再沧。
轉(zhuǎn)載請說明出處:http://www.reibang.com/p/efc0bebfd22e