Android-SurfaceView的總結
緣由:
Android系統提供View進行繪圖處理,但是很多時候會顯得心有餘而力不足,比如當view繪圖進行大量的操作,容易使主線程阻塞,並且在logcat輸出···
"skipped 47 frames! the application may be doing much work in main thread"
這個當我在頁面進行大量的視圖動畫時,經常出現。
所以當你的View需要頻繁的刷新,或者刷新時數據處理量比較大時,建議使用SurfaceView。
View繪圖方式:
View是通過刷新來更新視圖。系統通過發送VSYnc信號來通知屏幕進行刷新,刷新頻率爲16ms,因此當你的View刷新時間超過16ms,就會出現卡頓。
View和surfaceView的比較:
1.view適用於主動進行畫面更新,而surfaceView適合被動進行更新。
2.view更新運行在主線程,容易造成主線程的阻塞,而surfaceView運行在新的子線程中。
3.VIew繪圖沒有使用雙緩衝機制,而surfaceView底層已經實現雙緩衝機制。
說明:雙緩衝機制--當要在指定View上繪製圖形時,不直接在View上繪製,而是先繪製到內存中的Bitmap圖片上,等到緩存的Bitmap 繪製好,以後,再將bitmap上的直接繪製View組件上。
surfaceView的使用:
1.繼承自SurfaceView,實現SurfaceHolder,CallBack,Runnable接口
2.並且重寫抽象方法
2.在xml文件中使用或者動態生成
實例代碼:
public class KillView extends SurfaceView implements SurfaceHolder.Callback,Runnable{
private SurfaceHolder holder;
private Canvas canvas;
private boolean isDrawing;
private Paint paint;
public KillView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public KillView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public KillView(Context context) {
super(context);
init();
}
public void init(){
Log.e("TAG","init");
holder=getHolder();
holder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
}
Path path;
@Override
public void run() {
long start=System.currentTimeMillis();
while (isDrawing){
draw();
}
long end=System.currentTimeMillis();
Log.e("TAG","start="+start+" end="+end);
if(end-start<100){
try{
Thread.sleep(100-end+start);
}catch (Exception e){
e.printStackTrace();
}
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.e("TAG","create");
isDrawing=true;
path=new Path();
paint=new Paint();
paint.setColor(getResources().getColor(R.color.colorAccent));
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.e("TAG","change");
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e("TAG","destroy");
isDrawing=false;
}
public void draw(){
try{
canvas=holder.lockCanvas();
canvas.drawCircle(getWidth()/2,getWidth()/2,100,paint);
holder.unlockCanvasAndPost(canvas);
canvas=holder.lockCanvas();
canvas.drawColor(Color.WHITE);
//canvas.drawPath(path,paint);
canvas.drawArc(0,0,100,100,0,360,true,paint);
}catch (Exception e){
throw new IllegalArgumentException();
}finally{
if(holder!=null){
holder.unlockCanvasAndPost(canvas);
}
}
}
}
代碼中方法說明:
1.getHolder()
surfaceView 一般與surfaceHolder結合使用,surfaceHolder用於向關聯的View繪圖 ,可通過getHolder方法獲得當前View的holder。
2.lockCanvas()
鎖定surfaceView對象,獲取surfaceView上的Canvas對象。
3.unlockCanvasANdPost()
當調用該方法時,之前繪製的內容還在內存中,當下次lockCanvas()時,可能會覆蓋之前的內容,因此如果想要持久化繪製內容,添加以下代碼:
holder.lockcanvas(new Rect(0,0,0,0);
holder.unlockcanvasAndPost(canvas);