一详幽、為什么要SurfaceView
大多數(shù)情況下我們的自定義View都會(huì)選擇去繼承View或ViewGroup來實(shí)現(xiàn)盒音,但是為什么系統(tǒng)還要為我們提供一個(gè)SurfaceView呢驰徊?
首先我們知道View類如果需要更新視圖垛贤,必須我們主動(dòng)的去調(diào)用invalidate()或者postInvalidate()方法來再走一次onDraw()完成更新真朗。但是呢,Android系統(tǒng)規(guī)定屏幕的刷新間隔為16ms燃领,如果這個(gè)View在16ms內(nèi)更新完畢了士聪,就不會(huì)卡頓,但是如果邏輯操作太多猛蔽,16ms內(nèi)沒有更新完畢剥悟,剩下的操作就會(huì)丟到下一個(gè)16ms里去完成,這樣就會(huì)造成UI線程的阻塞,造成View的運(yùn)動(dòng)過程掉幀懦胞,自然就會(huì)卡頓了。
所以這些原因也就促使了SurfaceView的存在凉泄。畢竟躏尉,如果是一個(gè)游戲,它有可能相當(dāng)頻繁的有更新畫面的需求后众。
二胀糜、SuraceView的主要優(yōu)勢(shì)
1、SurfaceView的刷新處于主動(dòng)蒂誉,有利于頻繁的更新畫面教藻。
2、SurfaceView的繪制在子線程進(jìn)行右锨,避免了UI線程的阻塞括堤。
3、SurfaceView在底層實(shí)現(xiàn)了一個(gè)雙緩沖機(jī)制绍移,效率大大提升悄窃。
但是要提一點(diǎn)兒,SurfaceView也是View派生而來的蹂窖。
三轧抗、SurfaceView的使用
1、首先這個(gè)自定義的SurfaceView類必須繼承SurfaceView實(shí)現(xiàn)SurfaceHolder.Callback接口瞬测。
2横媚、實(shí)現(xiàn)SurfaceHolder.Callback中的三個(gè)SurfaceView生命周期,分別為:
surfaceCreated(SurfaceHolder holder)
surfaceChanged(SurfaceHolder holder, int format, int width, int height)
surfaceDestroyed(SurfaceHolder holder)
顧明思議月趟,不多解釋被回調(diào)的時(shí)機(jī)灯蝴。
3、在surfaceCreated方法里開啟一個(gè)子線程孝宗。
4绽乔、在這個(gè)子線程中開啟一個(gè)由Flag控制的While循環(huán),用于不斷地繪制碳褒。
5折砸、在循環(huán)中通過SurfaceHolder對(duì)象的lockCanvas方法獲得一個(gè)Canvas對(duì)象用于繪制。
6沙峻、每次繪制完成通過SurfaceHolder對(duì)象unlockCanvasAndPost方法傳入Canvas對(duì)象完成更新睦授。
7、最后要在surfaceDestroyed方法中去改變while循環(huán)的Flag為false摔寨,結(jié)束子線程的繪制去枷。
四、我們看一下完整的代碼例子:
public class PencilView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder mHolder;
private Canvas mCanvas;
private boolean mIsRunning;
public PencilView(Context context) {
this(context, null);
}
public PencilView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PencilView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mHolder = getHolder();
mHolder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mIsRunning = true;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsRunning = false;
}
@Override
public void run() {
long start = System.currentTimeMillis();
while (mIsRunning) {
draw();
}
}
private void draw() {
mCanvas = mHolder.lockCanvas();
if (mCanvas != null) {
try {
//使用獲得的Canvas做具體的繪制
} catch (Exception e) {
e.printStackTrace();
} finally {
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
}