1. 程式人生 > >SurfaceView的入門(一)----初始surfaceView

SurfaceView的入門(一)----初始surfaceView

轉載:https://blog.csdn.net/rong_wz/article/details/51956463

轉載:https://www.jianshu.com/p/acf574f08efc

轉載:https://blog.csdn.net/android_cmos/article/details/68955134

什麼是surface?           

         我們知道Activity是用了來顯示介面的,那麼Activity的介面是如何繪製出來的呢?這個肯定和Surface有關,但是博主是新手,具體關聯就不清楚,博主自己理解,Surface

就像螢幕上的一個畫布,canvas是一位畫家,paint就是一支筆,view其實就是由一位畫家canvas還有一些關於view自身的事件的組成的一個物件,有了canvas,就可以往surface上面作畫了,而每一個window對應一個Surface,任何View都是顯示在Surface上的,傳統的view共享一個surface,但因為view只能在ui執行緒更新,所以view裡面的畫手canvas消耗的時間是主執行緒出的(為什麼?因為如果多執行緒操作ui,就會涉及到同步和鎖之類的,這樣子效率就不高,所以系統把所有ui操作都在主執行緒執行,當操作ui時候,如果判斷不當前執行緒不是主執行緒,直接拋異常),
因此,用傳統ui做頻繁的更新操作,會引起執行緒的阻塞,從而造成卡頓,嚴重會出現無響應,所以這個時候,需要surfaceView

什麼是surfaceView?

   surfaceView本身繼承於view,符合view的所有特性,但是還不夠嚴謹,看下圖。


              

     

    上圖是SurfaceView原始碼,可以知道SurfaceView的建立會新建一個視窗,而這個newMyWindow(this)

this就是指的surfaceView物件本身,從上面知道,surfaceView有自己的window,上面說了,每個window對應一個surface,所以SurfaceView內嵌了一個自己的Surface,所以SurfaceView和傳統的view不是共用一個surface,並且和傳統的view還有不同的是,view是繪製在suface之上的,但是surfaceView是繪製在surface中,意思就像,一般的view就像在琥珀上面畫畫,surfaceView就是琥珀裡面的東西,另外,view的繪製用到的畫手消耗的時間是在主執行緒裡面出的,但是surfaceview畫圖,就像琥珀裡面的東西,它不用外在的畫上去所以不需要消耗主執行緒的時間,只需要內部的描繪出來,描繪出來的這段時間,可以用子執行緒來執行,所以surfaceView用來做遊戲,錄播播放還有一些頻繁更新的操作,因此surfaceView你可以理解為只是一個改變surface畫布大小和位置的一個view。.

 如何surfaceView?

      首先SurfaceView也是一個View,它也有自己的生命週期。因為它需要另外一個執行緒來執行繪製操作,所以我們可以在它生命週期的初始化階 段開闢一個新執行緒,然後開始執行繪製,當生命週期的結束階段我們插入結束繪製執行緒的操作。這些是由其內部一個SurfaceHolder物件完成的。  

      SurfaceView它的繪製原理是繪製前先鎖定畫布(獲取畫布),然後等都繪製結束以後在對畫布進行解鎖 ,最後在把畫布內容顯示到螢幕上。

      通常情況下,使用以下步驟來建立一個SurfaceView的模板:

  (1)建立SurfaceView

  建立自定義的SurfaceView繼承自SurfaceView,並實現兩個介面:SurfaceHolder.CallbackRunnable.程式碼如下

public class MySurfaceView extends SurfaceView implements Runnable,SurfaceHolder.Callback{

     通過實現這兩個介面,就需要在自定義的SurfaceView中實現介面的方法,對於SurfaceHolder.Callback方法,需要實現如下方法,其實就是SurfaceView的生命週期:

 @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mIsDrawing = true;
        new Thread(this).start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mIsDrawing = false;
    }

對於Runnable介面,需要實現run()方法,


 @Override
    public void run() {
        while (mIsDrawing){
            try {
                mCanvas = mHolder.lockCanvas();
                // draw sth繪製過程
            } catch (Exception e) {
            } finally {
                if (mCanvas != null)
                    mHolder.unlockCanvasAndPost(mCanvas);//保證每次都將繪圖的內容提交
            }
        }
    }

(2)初始化SurfaceView

       在自定義的MySurfaceView的構造方法中,需要對SurfaceView進行初始化,包括SurfaceHolder的初始化、畫筆的初始化等。在自定義的SurfaceView中,通常需要定義以下三個成員變數:

 private SurfaceHolder mHolder;
    private Canvas mCanvas;//繪圖的畫布
    private boolean mIsDrawing;//控制繪畫執行緒的標誌位

     SurfaceHolder,顧名思義,它裡面儲存了一個對Surface物件的引用,而我們執行繪製方法本質上就是操控Surface。SurfaceHolder因為儲存了對Surface的引用,所以使用它來處理Surface的生命週期。(說到底 SurfaceView的生命週期其實就是Surface的生命週期)例如使用 SurfaceHolder來處理生命週期的初始化。

初始化程式碼如下:

 public MySurfaceView(Context context) {
        super(context);
        initView();
    }

    private void initView() {
        mHolder = getHolder();//獲取SurfaceHolder物件
        mHolder.addCallback(this);//註冊SurfaceHolder的回撥方法
        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setKeepScreenOn(true);//保持螢幕常亮
    }

    public MySurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

(2)SurfaceView總體使用

package com.slide.aier.myview;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * Created by aier on 2018/6/23.
 */

public class MySurfaceView extends SurfaceView implements Runnable,SurfaceHolder.Callback{

    private SurfaceHolder mHolder;
    private Canvas mCanvas;//繪圖的畫布
    private boolean mIsDrawing;//控制繪畫執行緒的標誌位

    public MySurfaceView(Context context) {
        super(context);
        initView();
    }

    private void initView() {
        mHolder = getHolder();//獲取SurfaceHolder物件
        mHolder.addCallback(this);//註冊SurfaceHolder的回撥方法
        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setKeepScreenOn(true);//保持螢幕常亮
    }

    public MySurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mIsDrawing = true;
        new Thread(this).start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mIsDrawing = false;
    }

    @Override
    public void run() {
        while (mIsDrawing){
            try {
                mCanvas = mHolder.lockCanvas();
                // draw sth繪製過程
            } catch (Exception e) {
            } finally {
                if (mCanvas != null)
                    mHolder.unlockCanvasAndPost(mCanvas);//保證每次都將繪圖的內容提交
            }
        }
    }
}