Android中的Surface和SurfaceView之我見

來源:互聯網
上載者:User

一、什麼是Surface

           簡單的說Surface對應了一塊螢幕緩衝區,每個window對應一個Surface,任何View都要畫在Surface的Canvas上(後面有原因解釋)。傳統的view共用一塊螢幕緩衝區,所有的繪製必須在UI線程中進行。

        在SDK的文檔中,對Surface的描述是這樣的:“Handle onto a raw buffer that is being managed by the screen compositor”,翻譯成中文就是“由螢幕顯示內容合成器(screen compositor)所管理的原始緩衝區的控制代碼”,這句話包括下面兩個意思:

        1、通過Surface(因為Surface是控制代碼)就可以獲得原生緩衝器以及其中的內容。就像在C++語言中,可以通過一個檔案的控制代碼,就可以獲得檔案的內容一樣。

        2、 原始緩衝區(a raw buffer)是用於儲存當前視窗的像素資料的。

        引伸地,可以認為Android中的Surface就是一個用來畫圖形(graphics)或映像(image)的地方。

        根據Java方面的常規知識,我們知道通常畫圖是在一個Canvas對象上面進行的,由此,可以推知一個Surface對象中應該包含有一個Canvas(畫布)對象。因此,在前面提及的兩個意思的基礎上,可以再加上一條:

        3、Surface中有一個Canvas成員,專門用於畫圖的。

        由以上的概括,我們總結如下:Surface中的Canvas成員,是專門用於供程式員畫圖的場所,就像黑板一樣;其中的原始緩衝區是用來儲存資料的地方;Surface本身的作用類似一個控制代碼,得到了這個控制代碼就可以得到其中的Canvas、原始緩衝區以及其它方面的內容。

      Surface是用來管理資料的。(控制代碼)

二、什麼是SurfaceView

         說SurfaceView是一個View也許不夠嚴謹,然而從定義中pubilc classSurfaceView extends View{.....}顯示SurfaceView確實是派生自View,但是SurfaceView卻有自己的Surface,請看SurfaceView的源碼:

    if (mWindow == null) {            mWindow = new MyWindow(this);            mLayout.type = mWindowType;            mLayout.gravity = Gravity.LEFT|Gravity.TOP;            mSession.addWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,            mVisible ? VISIBLE : GONE, mContentInsets);       }  

        很明顯,每個SurfaceView建立的時候都會建立一個MyWindow,new MyWindow(this)中的this正是SurfaceView自身,因此將SurfaceView和window綁定在一起,由第一部分我們知道,一個window對應一個Surface,因此SurfaceView也就內嵌了一個自己的Surface,可以認為SurfaceView是用來控制Surface中View的位置和尺寸的。

         SurfaceView就是展示Surface中資料的地方,同時可以認為SurfaceView是用來控制Surface中View的位置和尺寸的。

        大家都知道,傳統View及其衍生類別的更新只能在UI線程,然而UI線程還同時處理其他互動邏輯,這就無法保證View更新的速度和幀率了,而SurfaceView可以用獨立的線程進行繪製,因此可以提供更高的幀率,例如遊戲,網路攝影機取景等情境就比較適合SurfaceView來實現。

三、什麼是SurfaceHolder

        SurfaceHolder是一個介面,其作用就像一個關於Surface的監聽器,提供訪問和控制SurfaceView內嵌的Surface 相關的方法。它通過三個回調方法,讓我們可以感知到Surface的建立、銷毀或者改變。

        在SurfaceView中有一個方法getHolder,可以很方便地獲得SurfaceView內嵌的Surface所對應的監聽器介面SurfaceHolder(有點拗口吧)。

        除下面將要提到的SurfaceHolder.Callback外,SurfaceHolder還提供了很多重要的方法,其中最重要的就是:

       1、abstract void addCallback(SurfaceHolder.Callbackcallback):為SurfaceHolder添加一個SurfaceHolder.Callback回調介面。

       2、abstract Canvas lockCanvas():擷取一個Canvas對象,並鎖定之。所得到的Canvas對象,其實就是Surface中一個成員。

       3、abstract Canvas lockCanvas(Rect  dirty):同上。但只鎖定dirty所指定的矩形地區,因此效率更高。

       4、abstract void unlockCanvasAndPost(Canvas  canvas):當修改Surface中的資料完成後,釋放同步鎖,並提交改變,然後將新的資料進行展示,同時Surface中相關資料會被丟失。

        2、3、4中的同步鎖機制的目的,就是為了在繪製的過程中,Surface中的資料不會被改變。lockCanvas是為了防止同一時刻多個線程對同一canvas寫入。

總結:從設計模式的高度來看,Surface、SurfaceView和SurfaceHolder實質上就是廣為人知的MVC,即Model-View-Controller。Model就是模型的意思,或者說是資料模型,或者更簡單地說就是資料,也就是這裡的Surface;View即視圖,代表使用者互動介面,也就是這裡的SurfaceView;SurfaceHolder很明顯可以理解為MVC中的Controller(控制器)。

四、什麼是SurfaceHolder.Callback

       
SurfaceHolder.Callback主要是當底層的Surface被建立、銷毀或者改變時提供回調通知,由於繪製必須在Surface被建立後才能進行,因此SurfaceHolder.Callback中的surfaceCreated
和surfaceDestroyed 就成了繪圖處理代碼的邊界。

       
SurfaceHolder.Callback中定義了三個介面方法:

        1、abstract void surfaceChanged(SurfaceHolder
holder, int format, int width, int height):當surface發生任何結構性的變化時(格式或者大小),該方法就會被立即調用。

        2、abstract void surfaceCreated(SurfaceHolder
holder):當surface對象建立後,該方法就會被立即調用。

        3、abstract
void  surfaceDestroyed(SurfaceHolder
holder):當surface對象在將要銷毀前,該方法會被立即調用。

五、執行個體示範

       
下面,我們通過一個非常簡單例子來實際感受一下,請留意代碼中的注釋:

        1、在Eclipse中建立一個Android
Project項目TestSurfaceView,並選擇產生預設的Activity TestSurfaceViewActivity

        2、建立一個繪製線程如下:

import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;importandroid.view.SurfaceHolder;// 繪製線程public class MyThread extends Thread{         private SurfaceHolder holder;         private boolean run;                 public  MyThread(SurfaceHolder holder)         {                   this.holder = holder;                   run = true;         }         @Override         public void run()         {                   int counter = 0;                   Canvas canvas = null;                   while(run)                   {                            // 具體繪製工作                            try                            {                                     // 擷取Canvas對象,並鎖定之                                     canvas= holder.lockCanvas();                                                                         // 設定Canvas對象的背景顏色                                     canvas.drawColor(Color.WHITE);                                                                         // 建立畫筆                                     Paint p = new Paint();                                     // 設定畫筆顏色                                     p.setColor(Color.BLACK);                                     // 設定文字大小                                     p.setTextSize(30);                                                                         // 建立一個Rect對象rect                                     Rect  rect = new Rect(100, 50, 380, 330);                                     // 在canvas上繪製rect                                     canvas.drawRect(rect,p);                                     // 在canvas上顯示時間                                     canvas.drawText("Interval = " + (counter++) + " seconds.", 100, 410, p);                                     Thread.sleep(1000);                            }                            catch(Exception e)                            {                                     e.printStackTrace();                            }                            finally                            {                                     if(canvas != null)                                     {                                               // 解除鎖定,並提交修改內容                                               holder.unlockCanvasAndPost(canvas);                                     }                            }                   }         }         public boolean isRun()         {                   return run;         }                 public void setRun(boolean run)         {                   this.run = run;         }}

      
3、自訂一個SurfaceView類如下:

import android.content.Context;import android.view.SurfaceHolder;import android.view.SurfaceView;public class MySurfaceView extends SurfaceView implements  SurfaceHolder.Callback{         private SurfaceHolder holder;         private MyThread myThread;                 public  MySurfaceView(Context context)         {                   super(context);                                     // 通過SurfaceView獲得SurfaceHolder對象                   holder = getHolder();                                     // 為holder添加回調結構SurfaceHolder.Callback                   holder.addCallback(this);                                     // 建立一個繪製線程,將holder對象作為參數傳入,這樣在繪製線程中就可以獲得holder                   // 對象,進而在繪製線程中可以通過holder對象獲得Canvas對象,並在Canvas上進行繪製                   myThread = new MyThread(holder);         }         // 實現SurfaceHolder.Callback介面中的三個方法,都是在主線程中調用,而不是在繪製線程中調用的         @Override         public void  surfaceChanged(SurfaceHolder holder, int format, int width, int height)         {         }         @Override         public void  surfaceCreated(SurfaceHolder holder)         {                   // 啟動線程。當這個方法調用時,說明Surface已經有效了                   myThread.setRun(true);                   myThread.start();         }         @Override         public void surfaceDestroyed(SurfaceHolder holder)         {                   // 結束線程。當這個方法調用時,說明Surface即將要被銷毀了                   myThread.setRun(false);         }}

        4、修改TestSurfaceViewActivity.java代碼,使之如下:

import android.app.Activity;import android.os.Bundle;public class TestSurfaceViewActivity extends Activity{    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        //setContentView(R.layout.main);        setContentView(new MySurfaceView(this));    }}

運行結果:



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.