聲明:此文非本人原創(chuàng),為整理網(wǎng)絡資料加自己的一些注解所得徊哑。
surface相當于畫板袜刷,所有的圖像(view及其子類)都是要畫在surface上的。每個surface會創(chuàng)建一個Canvas對象(其屬性是會時常變的)--一個用來管理view在surface上繪圖的操作莺丑。換句通俗的話講著蟹,surface是畫板,Canvas相當與話的動作梢莽,Paint相當于畫筆萧豆。因而Canvas中包含了很多畫的動作,比如話矩形昏名,畫圓等等涮雷。
SurfaceView是視圖(View)的繼承類,這個視圖里內(nèi)嵌了一個專門用于繪制的Surface葡粒。你可以控制這個Surface的格式和尺寸份殿。Surfaceview控制這個Surface的繪制位置。surface是縱深排序(Z-ordered)的嗽交,這表明它總在自己所在窗口的后面卿嘲。surface的排版顯示受到視圖層級關(guān)系的影響, surface的內(nèi)容會被它的兄弟視圖遮擋夫壁,這一特性可以用來放置遮蓋物(overlays)(例如拾枣,文本和按鈕等控件)『腥茫可以在主線程之外的線程中向屏幕繪圖梅肤。這樣可以避免畫圖任務繁重的時候造成主線程阻塞,從而提高了程序的反應速度邑茄。在游戲開發(fā)中多用到SurfaceView姨蝴,游戲中的背景、人物肺缕、動畫等等盡量在畫布canvas中畫出左医。
可以通過SurfaceHolder接口訪問這個surface授帕,getHolder()方法可以得到這個接口。 surfaceview變得可見時浮梢,surface被創(chuàng)建跛十;surfaceview隱藏前,surface被銷毀秕硝。這樣能節(jié)省資源芥映。如果你要查看 surface被創(chuàng)建和銷毀的時機,可以重載surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)远豺。
surfaceview的核心在于提供了兩個線程:UI線程和渲染線程奈偏。這里應注意:
1> 所有SurfaceView和SurfaceHolder.Callback的方法都應該在UI線程里調(diào)用,一般來說就是應用程序主線程憋飞。渲染線程所要訪問的各種變量應該作同步處理霎苗。
2> 由于surface可能被銷毀,它只在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()之間有效榛做,所以要確保渲染線程訪問的是合法有效的surface唁盏。
實現(xiàn):
繼承SurfaceView并實現(xiàn)SurfaceHolder.Callback接口,重寫:
1.surfaceChanged //在surface的大小發(fā)生改變時激發(fā)
2.surfaceCreated //在創(chuàng)建時激發(fā),一般在這里調(diào)用畫圖的線程检眯。
3.surfaceDestroyed //銷毀時激發(fā)厘擂,一般在這里將畫圖的線程停止、釋放锰瘸。
整個過程:繼承SurfaceView并實現(xiàn)SurfaceHolder.Callback接口 ----> SurfaceView.getHolder()獲得SurfaceHolder對象 ---->SurfaceHolder.addCallback(callback)添加回調(diào)函數(shù)---->SurfaceHolder.lockCanvas()獲得Canvas對象并鎖定畫布----> Canvas繪畫 ---->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)結(jié)束鎖定畫圖刽严,并提交改變,將圖形顯示避凝。
SurfaceHolder:
這里用到了一個類SurfaceHolder,可以把它當成surface的控制器舞萄,用來操縱surface。處理它的Canvas上畫的效果和動畫管削,控制表面倒脓,大小,像素等含思。
幾個需要注意的方法:
(1)崎弃、abstract void addCallback(SurfaceHolder.Callback callback);
// 給SurfaceView當前的持有者一個回調(diào)對象。
(2)含潘、abstract Canvas lockCanvas();
// 鎖定畫布饲做,一般在鎖定后就可以通過其返回的畫布對象Canvas,在其上面畫圖等操作了遏弱。
(3)盆均、abstract Canvas lockCanvas(Rect dirty);
// 鎖定畫布的某個區(qū)域進行畫圖等..因為畫完圖后,會調(diào)用下面的unlockCanvasAndPost來改變顯示內(nèi)容漱逸。
// 相對部分內(nèi)存要求比較高的游戲來說泪姨,可以不用重畫dirty外的其它區(qū)域的像素居砖,可以提高速度。
(4)驴娃、abstract void unlockCanvasAndPost(Canvas canvas);
// 結(jié)束鎖定畫圖,并提交改變循集。
View:顯示視圖唇敞,內(nèi)置畫布,提供圖形繪制函數(shù)咒彤、觸屏事件疆柔、按鍵事件函數(shù)等;必須在UI主線程內(nèi)更新畫面镶柱,速度較慢
SurfaceView:基于view視圖進行拓展的視圖類旷档,更適合2D游戲的開發(fā);是view的子類歇拆,類似使用雙緩機制鞋屈,在新的線程中更新畫面所以刷新界面速度比view快。
GLSurfaceView:基于SurfaceView視圖再次進行拓展的視圖類故觅,專用于3D游戲開發(fā)的視圖厂庇;是SurfaceView的子類,openGL專用输吏。加入了EGL的管理权旷,并自帶了渲染線程。
surfaceView = (SurfaceView) findViewById(R.id.surfaceview);
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
private void drawCanvas(Bitmap bitmap) {
Canvas canvas = surfaceView.getHolder().lockCanvas();
if (canvas != null) {
canvas.drawBitmap(bitmap, 0, 0, null);
surfaceView.getHolder().unlockCanvasAndPost(canvas);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mediaPlayer!=null){
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
mediaPlayer = null;
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(SplashActivity.this, Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.welcome));
mediaPlayer.setLooping(true);
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
mediaPlayer.setDisplay(surfaceView.getHolder());
mediaPlayer.prepareAsync();
}
} catch (IOException e) {
ToastUtils.ToastShortCenter(SplashActivity.this, e.getMessage());
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
});
關(guān)于MediaPlayer:
播放聲音可以用MediaPlayer和AudioTrack贯溅,兩者都提供了java API供應用開發(fā)者使用拄氯。其中最大的區(qū)別是MediaPlayer可以播放多種格式的聲音文件,例如 MP3它浅,AAC译柏,WAV,OGG罚缕,MIDI等艇纺。MediaPlayer會在framework層創(chuàng)建對應的音頻解碼器。而AudioTrack只能播放已 經(jīng)解碼的PCM流邮弹,如果是文件的話只支持wav格式的音頻文件黔衡,因為wav格式的音頻文件大部分都是PCM流。AudioTrack不創(chuàng)建解碼器腌乡,所以只 能播放不需要解碼的wav文件盟劫。MediaPlayer在framework層還是會創(chuàng)建AudioTrack,把解碼后 的PCM數(shù)流傳遞給AudioTrack与纽,AudioTrack再傳遞給AudioFlinger進行混音侣签,然后才傳遞給硬件播放塘装。
補充:SoundPool 則適合播放比較短的音頻片段,比如游戲聲音影所、按鍵聲蹦肴、鈴聲片段等等,它可以同時播放多個音頻;