Android系統(tǒng)提供了View進(jìn)行繪圖處理,View可以滿足大部分的繪圖需求,但在某些時(shí)候,卻也有些心有余而力不足。我們知道,View通過刷新來重繪視圖,然而刷新的間隔時(shí)間為16ms,如果在16ms內(nèi)View完成了你所需要執(zhí)行的所有操作,那么用戶在視覺上,就不會(huì)產(chǎn)生卡頓的感覺;而如果執(zhí)行的操作邏輯太多,特別是需要頻繁刷新的界面上,例如游戲界面,那么就會(huì)不斷阻塞主線程,從而導(dǎo)致畫面卡頓。SurfaceView由此應(yīng)運(yùn)而生。
一、SurfaceView與View的區(qū)別
- View主要適用于主動(dòng)更新的情況,而SurfaceView主要適用于被動(dòng)更新,例如頻繁地刷新
- View在主線程中對(duì)畫面進(jìn)行刷新,而SurfaceView通常會(huì)通過一個(gè)子線程來進(jìn)行頁面的刷新
- View在繪圖時(shí)沒有使用雙緩沖機(jī)制,而SurfaceView在底層實(shí)現(xiàn)機(jī)制中就已經(jīng)實(shí)現(xiàn)了雙緩沖機(jī)制
二、SurfaceView的使用
- 創(chuàng)建SurfaceView
創(chuàng)建自定義的SurfaceView繼承SurfaceView,并實(shí)現(xiàn)兩個(gè)接口——SurfaceHolder.Callback和Runnable
public class SurfaceViewTemplate extends Surface
implements SurfaceHolder.Callback, Runnable
接口SurfaceHolder.Callback需要實(shí)現(xiàn)的方法有:
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
// SurfaceView的創(chuàng)建
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
// SurfaceView的改變
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
// SurfaceView的銷毀
}
對(duì)于Runnable接口,需要實(shí)現(xiàn)run方法:
@Override
public void run() {
}
- 初始化SurfaceView
在自定義SurfaceView的構(gòu)造方法中,需要對(duì)SurfaceView進(jìn)行初始化。在自定義的SurfaceView中,通常需要定義以下三個(gè)成員變量,代碼如下所示:
// SurfaceHolder
private SurfaceHolder mHolder;
// 用于繪圖的Canvas
private Canvas mCanvas;
// 子線程標(biāo)志位
private boolean mIsDrawing;
獲取SurfaceView中的SurfaceHolder 對(duì)象,并為其添加相應(yīng)的回調(diào)方法:
mHolder = getHolder();
mHolder.addCallback(this);
- 使用SurfaceView
通過SurfaceHolder對(duì)象的lockCanvas()方法,就可以獲得當(dāng)前的Canvas繪圖對(duì)象。接下來就可以與在View中進(jìn)行的繪制操作一樣進(jìn)行繪制了。
PS: 獲取到的Canvas對(duì)象還是繼續(xù)上次的Canvas對(duì)象,而不是一個(gè)新的對(duì)象。因此,之前所有的繪圖操作都將會(huì)被保留,如果需要擦除,則可以在繪制前,通過drawColor() 方法來進(jìn)行清屏操作。
整個(gè)SurfaceView的模板代碼如下所示:
public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback, Runnable{
// SurfaceHolder
private SurfaceHolder mHolder;
// 用于繪圖的Canvas
private Canvas mCanvas;
// 子線程標(biāo)志位
private boolean mIsDrawing;
public SurfaceViewTemplate(Context context) {
super(context);
initView();
}
public SurfaceViewTemplate(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView(){
mHolder = getHolder();
mHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
setKeepScreenOn(true);
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
mIsDrawing = true;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mIsDrawing = false;
}
@Override
public void run() {
while (mIsDrawing){
draw();
}
}
private void draw(){
try {
mCanvas = mHolder.lockCanvas();
// draw something
}catch (Exception e){
}finally {
if (mCanvas != null){
// 放在finally 代碼塊中,保證每次都能講內(nèi)容提交
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
}