1. 程式人生 > >SurfaceView的煩惱(二)-部分重新整理與第一、二幀猜想

SurfaceView的煩惱(二)-部分重新整理與第一、二幀猜想

       上篇"SurfaceView的煩惱(一)-雙快取與清屏 "提供了一個解決辦法:每次畫的時候,先清屏然後再全部重新畫。這裡有兩重意思:清屏就把上次的殘留清除掉了,不會出現重疊現象;全部重新畫,資訊也就不會因為清屏而不全。這種辦法用起來很有效,不管SurfaceView的雙緩衝顯示(flip)的底層原理,也不會出現下面要說的“第一、二幀的猜想”的問題。

       辦法雖然有效,但對於一些每次只畫一小部分割槽域,且這些畫的區域不會重疊時,這辦法的效率性就很差了;而這種情況是希望在不全清屏的情況下,在原來的基礎上繼續畫。下面是測試程式碼,大部分程式碼與上篇的一樣,除了MyTimerTask中的run()方法:

main.xml

MySurfaceView.java

MyTimerTask.java

結果如下:

(1) 在MySurfaceView中,如果在Timer啟動前不先呼叫清屏(即把task.clearDraw()註釋掉),出現的結果是:

(2) 如果加上那句先清屏,則結果如下:

很明顯,第一個結果在一開始的時候缺少了一個藍塊,代表著有部分想要畫的資訊被沖掉了(或覆蓋掉了);第二個結果才是我們想要的結果。

(1) 從程式碼中可以看到,所畫的矩形的位置每次都不一樣,且每次畫的位置都不會和以前畫的區域重疊時,是可以使用遞增的方式去畫(即在保持原來的情況下再畫新的),這樣就不需要每次都全部重新畫了,效率也就提高了。

(2) 程式碼中貌似沒有什麼第一幀、第二幀的現象。其實一開始嘗試的時候,並不會想到在Timer啟動之前先清屏;而是在MyTimerTask中的run()方法使用count==0、count==1來測試第一幀、第二幀的情況。由於SurfaceView的原理全部是使用jni呼叫底層庫來實現的(使用了JAVA的程式碼沒有幾行),這代表著想要真正瞭解其原理,得深入到非JAVA程式碼中(目前我沒有什麼好辦法,如果有的話麻煩告訴我一下)。因而,在此只能進行一下猜想。

第一、二幀猜想:

      雖然部分更新的時候,每次畫canvas時都僅鎖住一小部分割槽域,但我猜想第一幀、第二幀是全部換的,而不僅僅是鎖住的那一小部分割槽域。這裡說的第一幀是第一次呼叫MyTimerTask的run()方法進行畫面板,這裡根據SurfaceView的雙緩衝原理中的交替顯示,整個螢幕大小的back buffer換到前面來(並把第一個藍方塊畫上),此時front buffer轉回後臺(此時front buffer是全屏黑的);第二次呼叫MyTimerTask的run()方法進行畫面板時,在front buffer中畫上白方塊並顯示(注意:由於front buffer之前並沒有方塊,第一個藍方塊是在back buffer中的),這時看到的現象是藍方塊被沖掉了,只剩白方塊。特殊的是,只有這兩幀是整個面板全部切換的,後面的front buffer、back buffer切換的空間變成了鎖定面板區域,由於鎖定的面板區域每次都是不一樣的小區域,這時雙緩衝的交替只有這一小部分割槽域,而不是整個螢幕;除了鎖定的區域,其它區域的內容保留。

      如果在Timer啟動前先清一下屏(實際上是為了呼叫holder.unlockCanvasAndPost(canvas)使得原來的back buffer先交換一下),然後再在此基礎上畫,就沒有問題了。所以在run()方法中使用讀數的方式,第一幀僅post,從第二幀開始畫真正的內容也是一樣的。

上面僅僅是猜想,只有真正深入到下面的程式碼中瞭解,才知道是否正確,如果有了解的朋友,不妨闡述一下。下面有兩個佐證:

(1) 在MyTimerTask中鎖定的區域rectDirty,如果直接傳到下面的畫方塊程式碼中canvas.drawRect(rectDirty, paint);,會發現一個比較有趣的現象:首先會看到螢幕背景變成全藍(不是全黑了),然後螢幕背景變成全白,此後螢幕背景顏色不再變化(一直是白的),方塊除了第一個藍塊沒有的話,其它的正常。這個現象是符合上面猜想的第一幀、第二幀現象,目前沒有弄清楚的是,為什麼背景整個顏色會被改變。把鎖定的區域大小再new一個同樣大小、起始座標相同的Rect來畫方塊就沒有問題。

(2) hellogv大牛寫的一個例子:http://blog.csdn.net/hellogv/archive/2010/11/03/5985090.aspx ,由於之前發現這個例子是部分重新整理的,所以重點學了一下。在我遇到第一、二幀那個問題時,回頭再看這個例子,思考它為什麼沒有這個問題。其實裡面恰好第一、二幀什麼都沒有畫而是直接顯示面板(即unlockCanvasAndPost(canvas) ),不知道這是特意這樣做的,還是有其它原因。