<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Android提供了View來進行繪圖處理,在大部分情況下,View都能滿足繪圖需求。大家都知道View是通過重新整理來重繪檢視,Android系統通過發出VSYNC訊號來進行螢幕的重繪,重新整理的間隔時間為16ms。如果在16ms內View完成了你所需要執行的所有操作,那麼使用者在視覺上,就不會產生卡頓的感覺;反之,如果操作的邏輯過多時,就會掉幀從而使得使用者感覺到卡頓。特別的需要頻繁重新整理的介面上,如遊戲(60FPS以上),就會不斷阻塞主執行緒,從而導致介面卡頓。而Android提供了SurfaceView來解決這種情況。
View | SurfaceView |
適用於主動更新 | 適用於被動重新整理 |
在主執行緒中進行畫面更新 | 通常通過一個子執行緒來進行畫面更新 |
繪圖中沒有使用雙緩衝機制 | 在底層實現中就實現了雙緩衝機制 |
比較了上面的不同之處,顯然可以發現,如果一個View需要頻繁的重新整理,或者在重新整理時資料處理量大(可能引起卡頓),可以考慮使用SurfaceView來替代View。
SurfaceView在使用的過程中,有一套模板程式碼,對於大部分的SurfaceView繪圖操作而言都可以套用,因此SurfaceView在使用過程中並不難。
其中值得注意的幾個點:。
兩個介面
SurfaceHolder.CallBack
Runnable
第一個介面中需要實現的方法分別對應於SurfaceView的生命週期,即建立、改變和銷燬。具體程式碼如下:
//Surface的生命週期 @Override public void surfaceCreated(SurfaceHolder holder) { } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { }
而第二介面需要實現run方法,用於在子執行緒中進行draw操作。
由於SurfaceView的基本操作比較簡單,這邊就直接給出了它的一個模板程式碼
package com.pignet.surfaceviewdemo; import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * Created by DB on 2017/6/9. */ public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback,Runnable{ private SurfaceHolder mHolder; private Canvas mCanvas; private boolean mIsDrawing; //構造方法 public SurfaceViewTemplate(Context context) { super(context); initView(); } public SurfaceViewTemplate(Context context, AttributeSet attrs) { super(context, attrs); } public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } private void initView() { mHolder=getHolder(); mHolder.addCallback(this); setFocusable(true); setFocusableInTouchMode(true); this.setKeepScreenOn(true); } @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){ draw(); //通過執行緒休眠以控制重新整理速度 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } private void draw() { try { mCanvas=mHolder.lockCanvas(); //初始化畫布並在畫布上畫一些東西 }catch (Exception e){ }finally { //判斷畫布是否為空,從而避免黑畫面情況 if(mCanvas!=null){ mHolder.unlockCanvasAndPost(mCanvas); } } } }
下面結合一個具體的範例,展現SurfaceView在繪圖中的效果(繪圖板,即通過監聽觸控事件完成內容的繪製)。
package com.pignet.surfaceviewdemo; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * Created by DB on 2017/6/9. */ public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback,Runnable { private static final String TAG="SurfaceView"; //SurfaceHolder private SurfaceHolder mHolder; //用於繪圖的Canvas private Canvas mCanvas; //子執行緒標誌位 private boolean mIsDrawing; //畫筆 private Paint mPaint; //路徑 private Path mPath; 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); mPath=new Path(); //初始化畫筆 mPaint=new Paint(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(6); mPaint.setAntiAlias(true); mPaint.setColor(Color.RED); setFocusable(true); setFocusableInTouchMode(true); this.setKeepScreenOn(true); } //Surface的生命週期 @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() { long start =System.currentTimeMillis(); while(mIsDrawing){ draw(); long end = System.currentTimeMillis(); if(end-start<100){ try{ Thread.sleep(100-end+start); } catch (InterruptedException e) { e.printStackTrace(); } } } } private void draw() { try{ //鎖定畫布並返回畫布物件 mCanvas=mHolder.lockCanvas(); //接下去就是在畫布上進行一下draw mCanvas.drawColor(Color.WHITE); mCanvas.drawPath(mPath,mPaint); }catch (Exception e){ }finally { //當畫布內容不為空時,才post,避免出現黑畫面的情況。 if(mCanvas!=null) mHolder.unlockCanvasAndPost(mCanvas); } } /** * 繪製觸控滑動路徑 * @param event MotionEvent * @return true */ @Override public boolean onTouchEvent(MotionEvent event) { int x=(int) event.getX(); int y= (int) event.getY(); switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.d(TAG, "onTouchEvent: down"); mPath.moveTo(x,y); break; case MotionEvent.ACTION_MOVE: Log.d(TAG, "onTouchEvent: move"); mPath.lineTo(x,y); break; case MotionEvent.ACTION_UP: Log.d(TAG, "onTouchEvent: up"); break; } return true; } /** * 清屏 * @return true */ public boolean reDraw(){ mPath.reset(); return true; } }
效果圖:
SurfaceView和View一大不同就是SurfaceView是被動重新整理的,但我們可以控制重新整理的影格率,而View並且通過invalidate方法通知系統來主動重新整理介面的,但是View的重新整理是依賴於系統的VSYSC訊號的,其影格率並不受控制,而且因為UI執行緒中的其他一些操作會導致掉幀卡頓。而對於SurfaceView而言,它是在子執行緒中繪製圖形,根據這一特性即可控制其顯示影格率,通過簡單地設定休眠時間,即可,並且由於在子執行緒中,一般不會引起UI卡頓。
Thread.sleep(50);即可以控制1s內重新整理20次
SurfaceView的雙緩衝機制:即對於每一個SurfaceView物件而言,有兩個獨立的graphic buffer。在Android SurfaceView的雙緩衝機制中是這樣實現的:
在Buffer A中繪製內容,然後讓螢幕顯示Buffer A;在下一個迴圈中,在Buffer B中繪製內容,然後讓螢幕顯示Buffer B,如此往復。而由於這個雙緩衝機制的存在,可能會引起閃屏現象,。在第一個"lockCanvas-drawCanvas-unlockCanvasAndPost "迴圈中,更新的是buffer A的內容;到下一個"lockCanvas-drawCanvas-unlockCanvasAndPost"迴圈中,更新的是buffer B的內容。 如果buffer A與buffer B中某個buffer內容為空,當螢幕輪流顯示它們時,就會出現畫面黑畫面閃爍現象。
出現黑畫面是因為buffer A與buffer B中一者內容為空,而且為空的一方還被post到了螢幕。於是有兩種解決思路:
1.不讓空buffer出現:每次向一個buffer寫完內容並post之後,順便用這個buffer的內容填充另一個buffer。這樣能保證兩個 buffer的內容是同步的,缺點是做了無用功,耗費效能。
2.不post空buffer到螢幕:當準備更新內容時,先判斷內容是否為空,只有非空時才啟動"lockCanvas-drawCanvas-unlockCanvasAndPost"這個流程。(上述模板和範例中即採用了這個方法)
以上就是Android系統view與SurfaceView的基本使用及區別分析的詳細內容,更多關於Android view與SurfaceView使用區別的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45