1. 程式人生 > >Android圖形系統之Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之間的聯絡

Android圖形系統之Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之間的聯絡

SurfaceHolder

結構

繼承關係

public interface SurfaceHolder

android.view.SurfaceHolder 

概述

抽象介面持有人顯示錶面。允許您控制面的大小和格式,編輯在suface的橡樹,並監測到變化。此介面通常可通過SurfaceView來實現

當一個執行緒使用不同於正在執行的執行緒的SurfaceView的介面時,你應該仔細閱讀lockCanvas()Callback.surfaceCreated()這兩個抽象函式

常量值

public static final int 

SURFACE_TYPE_GPU

常數已宣告不贊成使用,已過時。

被忽略,該常量值在需要時自動設定。

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_TYPE_NORMAL

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中游戲開發的誤區,不要老想著用Layoutview去實現,不要將某個遊戲

中的物件做成一個元件來處理。應該儘量想著在Canvas(畫布)中畫出遊戲戲中的背景、人物、動畫等...

SurfaceView提供直接訪問一個可畫圖的介面,可以控制在介面頂部的子檢視層。SurfaceView是提供給需要直接畫畫素而不是使用

窗體部件的應用使用的。Android圖形系統中一個重要的概念和線索是surfaceView及其子類(如TextView, Button

要畫在surface上。每個surface建立一個Canvas物件(但屬性時常改變),用來管理viewsurface上的繪圖操作,如畫點畫線。

還要注意的是,使用它的時候,一般都是出現在最頂層的

使用的SurfaceView的時候,一般情況下還要對其進行建立,銷燬,改變時的情況進行監視,這就要用到SurfaceHolder.Callback.


1、Surface

Surface

extends Object
implements Parcelable

Class Overview

Handle 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?在CODE上檢視程式碼片派生到我的程式碼片
  1. //@\frameworks\base\core\java\android\view\Surface.java
  2. // The mSurfaceControl will only be present for Surfaces used by the window
  3. // server or system processes. When this class is parceled we defer to the
  4. // mSurfaceControl to do the parceling. Otherwise we parcel the
  5. // mNativeSurface.
  6. privateint mSurfaceControl;  
  7. privateint mSaveCount;  
  8. private Canvas mCanvas;  
  9. privateint mNativeSurface;  
  10. privateint mSurfaceGenerationId;  
  11. private String mName;  

1.3、 理解Canvas物件,可以把它當做畫布,Canvas的方法大多數是設定畫布的大小、形狀、畫布背景顏色等等,要想在畫布上面畫畫,一般要與Paint物件結合使用,顧名思義,Paint就是畫筆的風格,顏料的色彩之類的。

[java] view plain copy  print?在CODE上檢視程式碼片派生到我的程式碼片
  1. // 建立畫筆  
  2. Paint paint = new Paint();    
  3. paint.setColor(Color.RED);// 設定紅色  
  4. canvas.drawCircle(602010, paint);// 畫一個圓  


1.4、Surface本身的作用類似一個控制代碼,得到了這個控制代碼就可以得到其中的Canvas、原生緩衝器以及其它方面的內容。

1.5、Surface實現了Parcelable介面,(implements Parcelable),也就是說Surface物件可以把顯示內容的資料寫入到 Parcel 中,並且能夠從Parcel讀回資料。


2、SurfaceView

SurfaceView

extends View

Class Overview

Provides 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:

  • All SurfaceView and  methods will be called from the thread running the SurfaceView's window (typically the main thread of the application). They thus need to correctly synchronize with any state that is also touched by the drawing thread.

簡單翻譯:

        SurfaceView提供了一個專門用於繪製的surface,這個surface內嵌於。你可以控制這個Surface的格式和尺寸。Surfaceview控制這個Surface在螢幕的