Ⅰ 對android中的surfaceview的困惑,雙緩沖區該怎麼理解
最近開發一款小游戲,需要用到surfaceView,出於效率的考慮,需要使用臟矩形刷新技術。一開始怎麼都不成功,到網上搜了很多有關臟矩形的使用的文章,但總是不懂。後來就只能到google上去搜索英文的相關文章,但是也收獲甚微。後來,直接看Android
Developers上面的解釋,也是一懂半懂的。canvas
= holder.lockCanvas(Rect
dirty);中定義臟矩形刷新。我的理解是,給定dirty之後,系統會自動把前一個畫布中dirty矩形外的部分拷貝過來,然後把dirty矩形內部留給現在的canvas來繪制。但是在項目的運行中,我發現根本不是這樣的,系統好像不會自動拷貝dirty之外的部分過來,因為我的背景圖片在繪制了一次之後,直接被黑色背景覆蓋了。我查了一下AndroidDevelopers上面有關這個臟矩形的講解,上面這樣介紹:Just
likelockCanvas()but allows
specification of a dirty rectangle. Every pixel within that
rectangle must be written; however pixels outside the dirty
rectangle will be preserved by the next call to
lockCanvas()。意思就是說:在矩形內的每一個像素必須都要被寫入,然後dirty矩形外的像素將在下次調用的時候保留。我在想,這個dirty臟矩形是不是為下次的繪圖而准備的?後來又仔細想了一會,結合網上的有關surfaceView的雙緩沖實現,我覺得可能問題是這樣的:第一次畫背景是畫在前景幀上,緩沖幀沒有。而第二次畫時,系統把緩沖幀與前景幀調換了,這樣由於之前的緩沖幀裡面沒有畫背景,就導致第二次繪畫中背景沒有畫出來。而第二次繪畫又是使用的臟矩形繪制,將在下一次繪制的時候保留臟矩形之外的部分,導致第三次繪畫時,雖然調出了最開始畫了背景的那一幀,但是臟矩形機制填充了臟矩形之外的部分,導致背景再次被覆蓋。自此,背景徹底從緩沖的兩幀中消失了。
找到了原因所在,解決就比較好辦了。直接在一開始的時候,調用兩遍繪制背景的函數,這樣保證緩沖的兩幀上面都有背景,那麼之後再用臟矩形,就沒有問題了。
當然,明白了這些,就不難解釋網上那些閃爍的問題的根源了。只需要在一開始把背景繪制兩遍即可。
在解決這個問題的過程中,通過所查的資料,以及我單步跟蹤調試,也發現了一個android的隱藏操作:就是在每次定製好臟矩形之後,android系統會自動重置臟矩形的大小尺寸(一般重置為當前整個畫布的大小),所以,為了能夠在下次循環的時候能夠繼續調用之前的臟矩形對象,就需要重置一下臟矩形的大小;或者還有一個辦法,就是直接寫一個函數,這個函數返回一個臟矩形的拷貝給canvas,這樣canvas就只能更改這個拷貝,而不能更改臟矩形對象本身了。