Android開發中的Surface庫及用其製作播放器UI的例子_Android

來源:互聯網
上載者:User

1、Surface
1.1、 就如在C語言編程一樣,通過一個檔案的控制代碼,就可以操作檔案,擷取檔案的內容。 同樣的,通過Surface就可以擷取raw buffer其中的內容。原生緩衝區(raw buffer)儲存著當前視窗的像素資料。

1.2、事實上,當得到一個Surface對象時,同時會得到一個Canvas(畫布)對象。這一點可以通過查看\frameworks\base\core\java\android\view\Surface.java檔案可知道Surface類定義了一個Canvas成員變數

private int mSurfaceControl; private int mSaveCount; private Canvas mCanvas; private int mNativeSurface; private int mSurfaceGenerationId; private String mName; 

1.3、 理解Canvas對象,可以把它當做畫布,Canvas的方法大多數是設定畫布的大小、形狀、畫布背景顏色等等,要想在畫布上面畫畫,一般要與Paint對象結合使用,顧名思義,Paint就是畫筆的風格,顏料的色彩之類的。

// 建立畫筆  Paint paint = new Paint();  paint.setColor(Color.RED);// 設定紅色   canvas.drawCircle(60, 20, 10, paint);// 畫一個圓  

1.4、Surface本身的作用類似一個控制代碼,得到了這個控制代碼就可以得到其中的Canvas、原生緩衝器以及其它方面的內容。

1.5、Surface實現了Parcelable介面,(implements Parcelable),也就是說Surface對象可以把顯示內容的資料寫入到 Parcel 中,並且能夠從Parcel讀回資料。

2、SurfaceView
SurfaceView提供了一個專門用於繪製的surface,這個surface內嵌於。你可以控制這個Surface的格式和尺寸。Surfaceview控制這個Surface在螢幕的正確繪製位置。
surface是Z-ordered的(也就是說在xyz座標系中,按照Z座標排序的,Z值大的表面覆蓋在Z值小的表面的上方),這表明它總在自己所在視窗的後面。surfaceview在顯示視窗處為Surface提供了一個可見地區,通過這個地區,才能看到Surface裡面的內容。可以放置一些覆蓋圖層(overlays)在Surface上面,如Button、Textview之類的。但是,需要注意的是,如果Surface上面有全透明的控制項,那麼隨著Surface的每一次變化,這些全透明的控制項就會重新渲染,這樣的話,就影響效能與顯示的效果。
你可以通過SurfaceHolder這個介面去訪問Surface,而執行getHolder()方法可以得到SurfaceHolder介面。
當SurfaceView的視窗可見時,Surface就會被建立,當SurfaceView視窗隱藏時,Surface就會被銷毀。當然了,你也可以通過複寫surfaceCreated(SurfaceHolder) 和 surfaceDestroyed(SurfaceHolder)  這兩個方法來驗證一下Surface何時被建立與何時被銷毀。
SurfaceView提供了一個運行在渲染線程的surface,若你要更新螢幕,你需要瞭解以下線程知識。
所有SurfaceView 和 SurfaceHolder.Callback的方法都應該在主線程(UI線程)裡面調用,應該要確保渲染進程所訪問變數的同步性。
你必須確保只有當Surface有效時候,(也就是當Surface的生命週期在SurfaceHolder.Callback.surfaceCreated() 和SurfaceHolder.Callback.surfaceDestroyed()之間)才能讓渲染進程訪問。

2.1、SurfaceView與Surface的聯絡
簡單來說,SurfaceView與Surface的聯絡就是,Surface是管理顯示內容的資料(implementsParcelable),包括儲存於資料的交換。而SurfaceView就是把這些資料顯示出來到螢幕上面。
兩者聯絡如圖所示:

3、SurfaceHolder
SurfaceHolder是控制surface的一個抽象介面,你可以通過SurfaceHolder來控制surface的尺寸和格式,或者修改surface的像素,監視surface的變化等等,SurfaceHolder是SurfaceView的典型介面。
與直接控制SurfaceView來修改surface不同,使用SurfaceHolder來修改surface時,需要注意lockCanvas() 和Callback.surfaceCreated().這兩個方法。
SurfaceHolder控制surface的流程所使用的幾個方法。

3.1、abstract void    addCallback(SurfaceHolder.Callback callback)
給SurfaceHolder一個回調對象。

3.2、abstract Canvas    lockCanvas(Rect dirty)
鎖定畫布中的某一個地區,返回的畫布對象Canvas(當更新的內容只有一個地區時,同時要追求高效,可以只更
新一部分的地區,而不必更新全部畫布地區)

3.3、abstract Canvas    lockCanvas()
鎖定畫布,返回的畫布對象Canvas

3.4、abstract void    removeCallback(SurfaceHolder.Callback callback)
移除回調對象

3.5、abstract void    unlockCanvasAndPost(Canvas canvas)
結束鎖定畫圖,並提交改變。

4、SurfaceHolder.Callback
SurfaceHolder.Callback是監聽surface改變的一個介面

4.1、public abstract voidsurfaceChanged(SurfaceHolder holder, int format, int width, int height)
surface發生改變時被調用

4.2、public abstract voidsurfaceCreated(SurfaceHolder holder)
在surface建立時被調用,一般在這個方法裡面開啟渲染螢幕的線程。

4.3、public abstract voidsurfaceDestroyed(SurfaceHolder holder)
銷毀時被調用,一般在這個方法裡將渲染的線程停止。

附上上述所說幾種的聯絡方法

SurfaceHolder = SurfaceView.getHolder();  Surface = SurfaceHolder.getSurface();  Canvas =SurfaceHolder.LockCanvas(Rect dirty)  Canvas  =Surface.lockCanvas(Rect dirty) 

5、DEMO:通過SurfaceView以及SurfaceHolder進行視頻播放
使用AudioView進行視頻播放的時候,是不是很不爽,千篇一律的模式,噁心吧。這裡,我們可以通過一些方式對MediaPlayer進行封裝。而所用到的正是SurfaceView以及SurfaceHolder。
最終效果圖:

我們提供了四個按鈕,可以進行播放控制。

布局檔案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 通過SurfaceView/SurfaceHolder實現自己的播放器  * @author chenzheng_java  * @since 2011/03/23  * @description 這裡進行一下補充說明,我們可以通過mediaplayer添加OnPreparedListener  * 以及OnCompletionListener等事件對準備好播放以及播放完成後的操作進行控制。  * 使用SurfaceView以及SurfaceHolder進行視頻播放時,結構是這樣的:  * 1、首先,我們從布局檔案中擷取一個surfaceView  * 2、通過surfaceView.getHolder()方法擷取與該容器想對應的surfaceHolder  * 3、對srufaceHolder進行一些預設的設定,如addCallback()和setType()  * 4、通過mediaPlayer.setDisplay()方法將視頻播放與播放容器連結起來  */ public class MyMediaPlayerActivity extends Activity {    MediaPlayer mediaPlayer ; // 播放器的內部實現是通過MediaPlayer   SurfaceView surfaceView ;// 裝在視頻的容器   SurfaceHolder surfaceHolder;// 控制surfaceView的屬性(尺寸、格式等)對象   boolean isPause ; // 是否已經暫停了      @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.media);     surfaceView = (SurfaceView) findViewById(R.id.surfaceView1);     /**      * 擷取與當前surfaceView相關聯的那個的surefaceHolder      */     surfaceHolder = surfaceView.getHolder();     /**      * 註冊當surfaceView建立、改變和銷毀時應該執行的方法      */     surfaceHolder.addCallback(new SurfaceHolder.Callback() {              @Override       public void surfaceDestroyed(SurfaceHolder holder) {         Log.i("通知", "surfaceHolder被銷毀了");         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被改變了");       }     });          /**      * 這裡必須設定為SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS哦,意思      * 是建立一個push的'surface',主要的特點就是不進行緩衝      */     surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);   }      /***    * @param targetButton 被使用者點擊的按鈕    */   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();     // 設定多媒體流類型     mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);          // 設定用於展示mediaPlayer的容器     mediaPlayer.setDisplay(surfaceHolder);     try {       mediaPlayer.setDataSource("/data/jinsha.3gp");       mediaPlayer.prepare();       mediaPlayer.start();       isPause = false;     } catch (Exception e) {       Log.i("通知", "播放過程中出現了錯誤哦");     }   }      /**    * 暫停    */   private void pause(){     Log.i("通知", "點擊了暫停按鈕");     if(isPause==false){       mediaPlayer.pause();       isPause=true;     }else{       mediaPlayer.start();       isPause=false;     }             }      /**    * 重設    */   private void reset(){     Log.i("通知", "點擊了reset按鈕");     // 跳轉到視頻的最開始     mediaPlayer.seekTo(0);     mediaPlayer.start();   }      /**    * 停止    */   private void stop(){     Log.i("通知", "點擊了stop按鈕");     mediaPlayer.stop();     mediaPlayer.release();        }    } 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.