1、Surface
1.1、 就如在C語(yǔ)言編程一樣,通過(guò)一個(gè)文件的句柄,就可以操作文件,獲取文件的內(nèi)容。 同樣的,通過(guò)Surface就可以獲取raw buffer其中的內(nèi)容。原生緩沖區(qū)(raw buffer)存儲(chǔ)著當(dāng)前窗口的像素?cái)?shù)據(jù)。
1.2、事實(shí)上,當(dāng)?shù)玫揭粋€(gè)Surface對(duì)象時(shí),同時(shí)會(huì)得到一個(gè)Canvas(畫(huà)布)對(duì)象。這一點(diǎn)可以通過(guò)查看/frameworks/base/core/java/android/view/Surface.java文件可知道Surface類(lèi)定義了一個(gè)Canvas成員變量
private int mSurfaceControl; private int mSaveCount; private Canvas mCanvas; private int mNativeSurface; private int mSurfaceGenerationId; private String mName;
1.3、 理解Canvas對(duì)象,可以把它當(dāng)做畫(huà)布,Canvas的方法大多數(shù)是設(shè)置畫(huà)布的大小、形狀、畫(huà)布背景顏色等等,要想在畫(huà)布上面畫(huà)畫(huà),一般要與Paint對(duì)象結(jié)合使用,顧名思義,Paint就是畫(huà)筆的風(fēng)格,顏料的色彩之類(lèi)的。
// 創(chuàng)建畫(huà)筆 Paint paint = new Paint(); paint.setColor(Color.RED);// 設(shè)置紅色 canvas.drawCircle(60, 20, 10, paint);// 畫(huà)一個(gè)圓
1.4、Surface本身的作用類(lèi)似一個(gè)句柄,得到了這個(gè)句柄就可以得到其中的Canvas、原生緩沖器以及其它方面的內(nèi)容。
1.5、Surface實(shí)現(xiàn)了Parcelable接口,(implements Parcelable),也就是說(shuō)Surface對(duì)象可以把顯示內(nèi)容的數(shù)據(jù)寫(xiě)入到 Parcel 中,并且能夠從Parcel讀回?cái)?shù)據(jù)。
2、SurfaceView
SurfaceView提供了一個(gè)專(zhuān)門(mén)用于繪制的surface,這個(gè)surface內(nèi)嵌于。你可以控制這個(gè)Surface的格式和尺寸。Surfaceview控制這個(gè)Surface在屏幕的正確繪制位置。
surface是Z-ordered的(也就是說(shuō)在xyz坐標(biāo)系中,按照Z(yǔ)坐標(biāo)排序的,Z值大的表面覆蓋在Z值小的表面的上方),這表明它總在自己所在窗口的后面。surfaceview在顯示窗口處為Surface提供了一個(gè)可見(jiàn)區(qū)域,通過(guò)這個(gè)區(qū)域,才能看到Surface里面的內(nèi)容。可以放置一些覆蓋圖層(overlays)在Surface上面,如Button、Textview之類(lèi)的。但是,需要注意的是,如果Surface上面有全透明的控件,那么隨著Surface的每一次變化,這些全透明的控件就會(huì)重新渲染,這樣的話(huà),就影響性能與顯示的效果。
你可以通過(guò)SurfaceHolder這個(gè)接口去訪(fǎng)問(wèn)Surface,而執(zhí)行g(shù)etHolder()方法可以得到SurfaceHolder接口。
當(dāng)SurfaceView的窗口可見(jiàn)時(shí),Surface就會(huì)被創(chuàng)建,當(dāng)SurfaceView窗口隱藏時(shí),Surface就會(huì)被銷(xiāo)毀。當(dāng)然了,你也可以通過(guò)復(fù)寫(xiě)surfaceCreated(SurfaceHolder) 和 surfaceDestroyed(SurfaceHolder)  這兩個(gè)方法來(lái)驗(yàn)證一下Surface何時(shí)被創(chuàng)建與何時(shí)被銷(xiāo)毀。
SurfaceView提供了一個(gè)運(yùn)行在渲染線(xiàn)程的surface,若你要更新屏幕,你需要了解以下線(xiàn)程知識(shí)。
所有SurfaceView 和 SurfaceHolder.Callback的方法都應(yīng)該在主線(xiàn)程(UI線(xiàn)程)里面調(diào)用,應(yīng)該要確保渲染進(jìn)程所訪(fǎng)問(wèn)變量的同步性。
你必須確保只有當(dāng)Surface有效的時(shí)候,(也就是當(dāng)Surface的生命周期在SurfaceHolder.Callback.surfaceCreated() 和SurfaceHolder.Callback.surfaceDestroyed()之間)才能讓渲染進(jìn)程訪(fǎng)問(wèn)。
2.1、SurfaceView與Surface的聯(lián)系
簡(jiǎn)單來(lái)說(shuō),SurfaceView與Surface的聯(lián)系就是,Surface是管理顯示內(nèi)容的數(shù)據(jù)(implementsParcelable),包括存儲(chǔ)于數(shù)據(jù)的交換。而SurfaceView就是把這些數(shù)據(jù)顯示出來(lái)到屏幕上面。
兩者聯(lián)系如圖所示:

3、SurfaceHolder
SurfaceHolder是控制surface的一個(gè)抽象接口,你可以通過(guò)SurfaceHolder來(lái)控制surface的尺寸和格式,或者修改surface的像素,監(jiān)視surface的變化等等,SurfaceHolder是SurfaceView的典型接口。
與直接控制SurfaceView來(lái)修改surface不同,使用SurfaceHolder來(lái)修改surface時(shí),需要注意lockCanvas() 和Callback.surfaceCreated().這兩個(gè)方法。
SurfaceHolder控制surface的流程所使用的幾個(gè)方法。
3.1、abstract void    addCallback(SurfaceHolder.Callback callback)
給SurfaceHolder一個(gè)回調(diào)對(duì)象。
3.2、abstract Canvas    lockCanvas(Rect dirty)
鎖定畫(huà)布中的某一個(gè)區(qū)域,返回的畫(huà)布對(duì)象Canvas(當(dāng)更新的內(nèi)容只有一個(gè)區(qū)域時(shí),同時(shí)要追求高效,可以只更
新一部分的區(qū)域,而不必更新全部畫(huà)布區(qū)域)
3.3、abstract Canvas    lockCanvas()
鎖定畫(huà)布,返回的畫(huà)布對(duì)象Canvas
3.4、abstract void    removeCallback(SurfaceHolder.Callback callback)
移除回調(diào)對(duì)象
3.5、abstract void    unlockCanvasAndPost(Canvas canvas)
結(jié)束鎖定畫(huà)圖,并提交改變。
4、SurfaceHolder.Callback
SurfaceHolder.Callback是監(jiān)聽(tīng)surface改變的一個(gè)接口
4.1、public abstract voidsurfaceChanged(SurfaceHolder holder, int format, int width, int height)
surface發(fā)生改變時(shí)被調(diào)用
4.2、public abstract voidsurfaceCreated(SurfaceHolder holder)
在surface創(chuàng)建時(shí)被調(diào)用,一般在這個(gè)方法里面開(kāi)啟渲染屏幕的線(xiàn)程。
4.3、public abstract voidsurfaceDestroyed(SurfaceHolder holder)
銷(xiāo)毀時(shí)被調(diào)用,一般在這個(gè)方法里將渲染的線(xiàn)程停止。
附上上述所說(shuō)幾種的聯(lián)系方法
SurfaceHolder = SurfaceView.getHolder(); Surface = SurfaceHolder.getSurface(); Canvas =SurfaceHolder.LockCanvas(Rect dirty) Canvas =Surface.lockCanvas(Rect dirty)
5、DEMO:通過(guò)SurfaceView以及SurfaceHolder進(jìn)行視頻播放
使用AudioView進(jìn)行視頻播放的時(shí)候,是不是很不爽,千篇一律的模式,惡心吧。這里,我們可以通過(guò)一些方式對(duì)MediaPlayer進(jìn)行包裝。而所用到的正是SurfaceView以及SurfaceHolder。
最終效果圖:

我們提供了四個(gè)按鈕,可以進(jìn)行播放控制。
布局文件media.xml代碼:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <SurfaceView android:id="@+id/surfaceView1" android:layout_width="320px" android:layout_height="160px"></SurfaceView> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <ImageButton android:id="@+id/button_play" android:src="@drawable/play" android:onClick="buttonClick" android:layout_width="wrap_content" android:layout_height="wrap_content"></ImageButton> <ImageButton android:id="@+id/button_pause" android:src="@drawable/pause" android:onClick="buttonClick" android:layout_width="wrap_content" android:layout_height="wrap_content"></ImageButton> <ImageButton android:id="@+id/button_stop" android:src="@drawable/stop" android:onClick="buttonClick" android:layout_width="wrap_content" android:layout_height="wrap_content"></ImageButton> <ImageButton android:id="@+id/button_reset" android:src="@drawable/reset" android:onClick="buttonClick" android:layout_width="wrap_content" android:layout_height="wrap_content"></ImageButton> </LinearLayout> </LinearLayout>
activity代碼:
package cn.com.chenzheng_java.media;  import android.app.Activity; import android.media.AudioManager; import android.media.MediaPlayer; import android.os.Bundle; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; /**  * @description 通過(guò)SurfaceView/SurfaceHolder實(shí)現(xiàn)自己的播放器  * @author chenzheng_java  * @since 2011/03/23  * @description 這里進(jìn)行一下補(bǔ)充說(shuō)明,我們可以通過(guò)mediaplayer添加OnPreparedListener  * 以及OnCompletionListener等事件對(duì)準(zhǔn)備好播放以及播放完成后的操作進(jìn)行控制。  * 使用SurfaceView以及SurfaceHolder進(jìn)行視頻播放時(shí),結(jié)構(gòu)是這樣的:  * 1、首先,我們從布局文件中獲取一個(gè)surfaceView  * 2、通過(guò)surfaceView.getHolder()方法獲取與該容器想對(duì)應(yīng)的surfaceHolder  * 3、對(duì)srufaceHolder進(jìn)行一些默認(rèn)的設(shè)置,如addCallback()和setType()  * 4、通過(guò)mediaPlayer.setDisplay()方法將視頻播放與播放容器鏈接起來(lái)  */ public class MyMediaPlayerActivity extends Activity {    MediaPlayer mediaPlayer ; // 播放器的內(nèi)部實(shí)現(xiàn)是通過(guò)MediaPlayer   SurfaceView surfaceView ;// 裝在視頻的容器   SurfaceHolder surfaceHolder;// 控制surfaceView的屬性(尺寸、格式等)對(duì)象   boolean isPause ; // 是否已經(jīng)暫停了      @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.media);     surfaceView = (SurfaceView) findViewById(R.id.surfaceView1);     /**      * 獲取與當(dāng)前surfaceView相關(guān)聯(lián)的那個(gè)的surefaceHolder      */     surfaceHolder = surfaceView.getHolder();     /**      * 注冊(cè)當(dāng)surfaceView創(chuàng)建、改變和銷(xiāo)毀時(shí)應(yīng)該執(zhí)行的方法      */     surfaceHolder.addCallback(new SurfaceHolder.Callback() {              @Override       public void surfaceDestroyed(SurfaceHolder holder) {         Log.i("通知", "surfaceHolder被銷(xiāo)毀了");         if(mediaPlayer!=null)         mediaPlayer.release();       }              @Override       public void surfaceCreated(SurfaceHolder holder) {         Log.i("通知", "surfaceHolder被create了");       }              @Override       public void surfaceChanged(SurfaceHolder holder, int format, int width,           int height) {         Log.i("通知", "surfaceHolder被改變了");       }     });          /**      * 這里必須設(shè)置為SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS哦,意思      * 是創(chuàng)建一個(gè)push的'surface',主要的特點(diǎn)就是不進(jìn)行緩沖      */     surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);   }      /***    * @param targetButton 被用戶(hù)點(diǎn)擊的按鈕    */   public void buttonClick(View targetButton){     int buttonId = targetButton.getId();     switch (buttonId) {     case R.id.button_play:       play();       break;     case R.id.button_pause:       pause();       break;     case R.id.button_reset:       reset();       break;     case R.id.button_stop:       stop();       break;     default:       break;     }        }      /**    * 播放    */   private void play(){          mediaPlayer = new MediaPlayer();     // 設(shè)置多媒體流類(lèi)型     mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);          // 設(shè)置用于展示mediaPlayer的容器     mediaPlayer.setDisplay(surfaceHolder);     try {       mediaPlayer.setDataSource("/data/jinsha.3gp");       mediaPlayer.prepare();       mediaPlayer.start();       isPause = false;     } catch (Exception e) {       Log.i("通知", "播放過(guò)程中出現(xiàn)了錯(cuò)誤哦");     }   }      /**    * 暫停    */   private void pause(){     Log.i("通知", "點(diǎn)擊了暫停按鈕");     if(isPause==false){       mediaPlayer.pause();       isPause=true;     }else{       mediaPlayer.start();       isPause=false;     }             }      /**    * 重置    */   private void reset(){     Log.i("通知", "點(diǎn)擊了reset按鈕");     // 跳轉(zhuǎn)到視頻的最開(kāi)始     mediaPlayer.seekTo(0);     mediaPlayer.start();   }      /**    * 停止    */   private void stop(){     Log.i("通知", "點(diǎn)擊了stop按鈕");     mediaPlayer.stop();     mediaPlayer.release();        }    } 新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注