Android圖形系統之Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之間的聯絡
SurfaceHolder
結構
繼承關係
public interface SurfaceHolder
android.view.SurfaceHolder
概述
抽象介面持有人顯示錶面。允許您控制面的大小和格式,編輯在suface的橡樹,並監測到變化。此介面通常可通過SurfaceView類來實現。
當一個執行緒使用不同於正在執行的執行緒的SurfaceView的介面時,你應該仔細閱讀lockCanvas()和Callback.surfaceCreated()這兩個抽象函式
常量值
public static final int
常數已宣告不贊成使用,已過時。
被忽略,該常量值在需要時自動設定。
Surface型別:建立適用於GPU加速的Surface
常量值:2 (0x00000002)
public static final int SURFACE_TYPE_HARDWARE
常數已宣告不贊成使用,已過時。
被忽略,該常量值在需要時自動設定。
Surface型別:建立適用於DMA(Direct memory access )引擎和硬體加速的Surface
常量值:1 (0x00000001)
public static final int
Surface型別:建立用RAM快取原生資料的普通Surface
常量值:0 (0x00000000)
public static final int SURFACE_TYPE_PUSH_BUFFERS
Surface型別:建立一個不包含原生資料Surface,Surface用到的資料由其他物件提供。如果設定這種型別則就不能呼叫lockCanvas來獲取Canvas物件了,否則將出現錯誤。
常量值:3 (0x00000003)
公共方法
public abstract void addCallback (SurfaceHolder.Callback callback)
給Surface持有者添加回調介面,一個持有者可以關聯多個回撥介面。
引數
callback 新的回撥介面
public abstract Surface getSurface ()
直接獲取Surface物件,這個Surface物件並不總是能獲取的。
例如:當使用SurfaceView, Surface的持有者直到該View隸屬於當前視窗管理器,確認佈局大小和螢幕的位置後才進行建立,你通常需要實現Callback.surfaceCreated尋找出可用的Surface。
注意,如果你通過另外的執行緒直接訪問Surface,關鍵在於你正確的實現了Callback.surfaceCreated 和Callback.surfaceDestroyed 函式來確保你訪問的執行緒的Surface是可用的,有效的,當一個執行緒正在使用該Surface,將不能得到釋放,銷燬。
這個方法的目的是用於經常需要直接訪問Surface物件的框架(通常是通過原生代碼),在設計API時總使用SurfaceHolder來改變Surface,而不是Surface物件本身。一個經驗規則是應用程式程式碼不能呼叫該方法
返回
Surface物件
public abstract Rect getSurfaceFrame ()
檢索當前Surface的大小
注意:不能修改發揮矩形區域大小,這是唯一安全的呼叫從SurfaceView的視窗執行緒,否則就需要放在lockCanvas()裡面呼叫。
返回
Suface的矩形尺寸,左側和頂部總為0
public abstract boolean isCreating ()
使用這個方法是來確定在程序中的Surface是否通過Callback方法正被建立,這是為了確定surfaceChanged(SurfaceHolder, int, int, int).方法是否能用。
返回
True 程序裡的Suface正被建立
public abstract Canvas lockCanvas ()
開始編輯surface的畫素,返回可以用來畫到表面的點陣圖的Canvas。如果表面尚未建立或無法進行編輯將返回null。通常需要實現Callback.surfaceCreated找出Surface時方可使用。
Surface的內容再從呼叫unlockCanvas() 和 lockCanvas(),之間被儲存,為此,在Surface區域內的沒有個畫素都將被畫出,僅一個例外是當髒矩形被指定的時候,非髒畫素將會被儲存。
如果當Surface沒有初始化(Callback.surfaceCreated之前或者Callback.surfaceDestroyed之後),你反覆呼叫它,為了避免耗費CPU,這些呼叫將以緩慢的速度被殺死。
如果沒有返回null值,這個函式在內部直到呼叫unlockCanvasAndPost(Canvas)函式,才持有鎖,來防止SurfaceView在繪製的時候被建立,銷燬,或者修改surface,因為當呼叫Callback.surfaceDestroyed你不需要建立一個特殊的同步繪製執行緒 所以你能更方便的直接訪問這個Sufrace
返回
用來進行繪製的Canvas
public abstract Canvas lockCanvas (Rect dirty)
和lockCanvas()一樣,但允許指定一個髒矩形,再這個矩形的每個畫素都必須被繪製,髒矩形外的畫素將被儲存直到下次呼叫lockCanvas()。
引數
dirty 將被修改的Surface區域
返回
用來進行繪製的Canvas
參見
lockCanvas ()
public abstract void removeCallback (SurfaceHolder.Callback callback)
從Surface持有者中刪除先前新增的回撥介面
引數
callback 要刪除的回撥介面
public abstract void setFixedSize (int width, int height)
使surface固定大小,他將永遠不能該表大小,當和SurfaceView一起工作時,這必須被同一執行的SurfaceView的視窗執行緒來呼叫
引數
width surface的寬.
height surface的高.
public abstract void setFormat (int format)
設定surface所需的畫素格式。預設是不透明的,當和SurfaceView一起工作時,這必須被同一執行的SurfaceView的視窗執行緒來呼叫
引數
format PixelFormat的常量.
參見
public abstract void setKeepScreenOn (boolean screenOn)
當surface被顯示的時候是否啟用或禁用螢幕保持開啟狀態,預設是禁用,允許螢幕關閉,啟用選項有效時,可以安全的呼叫任何執行緒。
引數
screenOn 為ture時強制螢幕保持開啟狀態,fasle允許氣關閉
public abstract void setSizeFromLayout ()
允許suface基於容器的佈局來改變大小(這是預設的),當啟用此功能,就應該監視surfaceChanged(SurfaceHolder, int, int, int)應對suface的大小變化,當和SurfaceView一起工作時,這必須被同一執行的SurfaceView的視窗執行緒來呼叫
public abstract void setType (int type)
設定該surface的型別
引數
type 該surface的記憶體型別
public abstract void unlockCanvasAndPost (Canvas canvas)
在surface完成編輯畫素,該函式呼叫後,surface的當前畫素就會在螢幕上顯示,但是它的資料會丟失,尤其是沒有保證surface資料保持不變的時候再次呼叫lockCanvas()。
引數
canvas 先前呼叫lockCanvas()返回的Canvas
參考
lockCanvas()
補充
在用SurfaceView進行遊戲開發過程中,用到SurfaceHolder來處理它的Canvas上畫的效果和動畫是必不可少的。用於控制表面,大小,畫素等。其中特別要注意以下的幾個函式:abstract void addCallback(SurfaceHolder.Callback callback);
// 給SurfaceView當前的持有者一個回撥物件。
abstract Canvas lockCanvas();
// 鎖定畫布,一般在鎖定後就可以通過其返回的畫布物件Canvas,在其上面畫圖等操作了。
abstract Canvas lockCanvas(Rect dirty);
// 鎖定畫布的某個區域進行畫圖等..因為畫完圖後,會呼叫下面的unlockCanvasAndPost來改變顯示內容。// 相對部分記憶體要求比較高的遊戲來說,可以不用重畫dirty外的其它區域的畫素,可以提高速度。
abstract void unlockCanvasAndPost(Canvas canvas);// 結束鎖定畫圖,並提交改變。
在android中開發遊戲,一般來說,或想寫一個複雜一點的遊戲,是必須用到SurfaceView來開發的。
經過這一陣子對android的學習,我找到了自已在android中游戲開發的誤區,不要老想著用Layout和view去實現,不要將某個遊戲
中的物件做成一個元件來處理。應該儘量想著在Canvas(畫布)中畫出遊戲戲中的背景、人物、動畫等...
SurfaceView提供直接訪問一個可畫圖的介面,可以控制在介面頂部的子檢視層。SurfaceView是提供給需要直接畫畫素而不是使用
窗體部件的應用使用的。Android圖形系統中一個重要的概念和線索是surface。View及其子類(如TextView, Button)
要畫在surface上。每個surface建立一個Canvas物件(但屬性時常改變),用來管理view在surface上的繪圖操作,如畫點畫線。
還要注意的是,使用它的時候,一般都是出現在最頂層的
使用的SurfaceView的時候,一般情況下還要對其進行建立,銷燬,改變時的情況進行監視,這就要用到SurfaceHolder.Callback.
1、Surface
Surfaceextends Objectimplements Parcelable Class OverviewHandle onto a raw buffer that is being managed by the screen compositor. 簡單翻譯: Surface是原始影象緩衝區(raw buffer)的一個控制代碼,而原始影象緩衝區是由螢幕影象合成器(screen compositor)管理的。 |
1.1、 就如在C語言程式設計一樣,通過一個檔案的控制代碼,就可以操作檔案,獲取檔案的內容。 同樣的,通過Surface就可以獲取raw buffer其中的內容。原生緩衝區(raw buffer)儲存著當前視窗的畫素資料。
1.2、事實上,當得到一個Surface物件時,同時會得到一個Canvas(畫布)物件。這一點可以通過檢視\frameworks\base\core\Java\Android\view\Surface.java檔案可知道Surface類定義了一個Canvas成員變數
[java] view plain copy print?- //@\frameworks\base\core\java\android\view\Surface.java
- // The mSurfaceControl will only be present for Surfaces used by the window
- // server or system processes. When this class is parceled we defer to the
- // mSurfaceControl to do the parceling. Otherwise we parcel the
- // mNativeSurface.
- privateint mSurfaceControl;
- privateint mSaveCount;
- private Canvas mCanvas;
- privateint mNativeSurface;
- privateint mSurfaceGenerationId;
- private String mName;
1.3、 理解Canvas物件,可以把它當做畫布,Canvas的方法大多數是設定畫布的大小、形狀、畫布背景顏色等等,要想在畫布上面畫畫,一般要與Paint物件結合使用,顧名思義,Paint就是畫筆的風格,顏料的色彩之類的。
[java] view plain copy print?- // 建立畫筆
- Paint paint = new Paint();
- paint.setColor(Color.RED);// 設定紅色
- canvas.drawCircle(60, 20, 10, paint);// 畫一個圓
1.4、Surface本身的作用類似一個控制代碼,得到了這個控制代碼就可以得到其中的Canvas、原生緩衝器以及其它方面的內容。
1.5、Surface實現了Parcelable介面,(implements Parcelable),也就是說Surface物件可以把顯示內容的資料寫入到 Parcel 中,並且能夠從Parcel讀回資料。
2、SurfaceView
SurfaceViewextends ViewClass OverviewProvides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed. The view hierarchy will take care of correctly compositing with the Surface any siblings of the SurfaceView that would normally appear on top of it. This can be used to place overlays such as buttons on top of the Surface, though note however that it can have an impact on performance since a full alpha-blended composite will be performed each time the Surface changes. Access to the underlying surface is provided via the SurfaceHolder interface, which can be retrieved by calling. The Surface will be created for you while the SurfaceView's window is visible; you should implementand to discover when the Surface is created and destroyed as the window is shown and hidden. One of the purposes of this class is to provide a surface in which a secondary thread can render into the screen. If you are going to use it this way, you need to be aware of some threading semantics:
簡單翻譯: |