SurfaceView和MediaPlayer

簡述

今天主要學習了SurfaceView和MediaPlayer的相關知識。

視頻的原理

視頻:1秒鐘大概播放24張圖片,加上配音和視頻信號,就形成一個視頻。平常一個Activity中加載完一個布局就不動了,那么如果在1秒鐘有24個這樣的頁面去渲染,即1秒鐘渲染24張畫面,就形成動畫了,1秒鐘渲染這么多畫面必定很消耗資源,因此不能在主線程中去做。

SurfaceView

SurfaceView是視圖(View)的繼承類,這個視圖里內嵌了一個專門用于繪制的Surface。你可以控制這個Surface的格式和尺寸。Surfaceview控制這個Surface的繪制位置。

surface是縱深排序(Z-ordered)的,這表明它總在自己所在窗口的后面。surfaceview提供了一個可見區域,只有在這個可見區域內 的surface部分內容才可見,可見區域外的部分不可見。surface的排版顯示受到視圖層級關系的影響,它的兄弟視圖結點會在頂端顯示。這意味者 surface的內容會被它的兄弟視圖遮擋,這一特性可以用來放置遮蓋物(overlays)(例如,文本和按鈕等控件)。注意,如果surface上面 有透明控件,那么它的每次變化都會引起框架重新計算它和頂層控件的透明效果,這會影響性能。

SurfaceView默認使用雙緩沖技術,它支持在子線程中繪制圖像,這樣就不會阻塞主線程了,所以它更適合于游戲和視頻播放器的開發。

繼承SurfaceView需要實現SurfaceHolder.Callback接口,且需要重寫其三個方法:

(1)public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}
//在surface的大小發生改變時激發

(2)public void surfaceCreated(SurfaceHolder holder){}
//在創建時激發,一般在這里調用畫圖的線程。

(3)public void surfaceDestroyed(SurfaceHolder holder) {}
//銷毀時激發,一般在這里將畫圖的線程停止、釋放。

MediaPlayer

用來播放音視頻的類,負責和底層打交道,最終解碼的是底層。MediaPlayer中封裝了很多方法,如start()、pause()、stop()等,它可以播放本地、網絡的音視頻,播放網絡視頻的時候需要聯網權限。

  • 執行流程(MediaPlayer的生命周期)

這張狀態轉換圖清晰的描述了MediaPlayer的各個狀態,也列舉了主要的方法的調用時序,每種方法只能在一些特定的狀態下使用,如果使用時MediaPlayer的狀態不正確則會引發IllegalStateException異常。

Idle狀態:當使用new()方法創建一個MediaPlayer對象或者調用了其reset()方法時,該MediaPlayer對象處于idle狀態。這兩種方法的一個重要差別就是:如果在這個狀態下調用了getDuration()等方法(相當于調用時機不正確),通過reset()方法進入idle狀態的話會觸發OnErrorListener.onError(),并且MediaPlayer會進入Error狀態;如果是新創建的MediaPlayer對象,則并不會觸發onError(),也不會進入Error狀態。

End狀態:通過release()方法可以進入End狀態,只要MediaPlayer對象不再被使用,就應當盡快將其通過release()方法釋放掉,以釋放相關的軟硬件組件資源,這其中有些資源是只有一份的(相當于臨界資源)。如果MediaPlayer對象進入了End狀態,則不會在進入任何其他狀態了。

Initialized狀態:這個狀態比較簡單,MediaPlayer調用setDataSource()方法就進入Initialized狀態,表示此時要播放的文件已經設置好了。

Prepared狀態:初始化完成之后還需要通過調用prepare()或prepareAsync()方法,這兩個方法一個是同步的一個是異步的,只有進入Prepared狀態,才表明MediaPlayer到目前為止都沒有錯誤,可以進行文件播放。

Preparing狀態:這個狀態比較好理解,主要是和prepareAsync()配合,如果異步準備完成,會觸發OnPreparedListener.onPrepared(),進而進入Prepared狀態。

Started狀態:顯然,MediaPlayer一旦準備好,就可以調用start()方法,這樣MediaPlayer就處于Started狀態,這表明MediaPlayer正在播放文件過程中。可以使用isPlaying()測試MediaPlayer是否處于了Started狀態。如果播放完畢,而又設置了循環播放,則MediaPlayer仍然會處于Started狀態,類似的,如果在該狀態下MediaPlayer調用了seekTo()或者start()方法均可以讓MediaPlayer停留在Started狀態。

Paused狀態:Started狀態下MediaPlayer調用pause()方法可以暫停MediaPlayer,從而進入Paused狀態,MediaPlayer暫停后再次調用start()則可以繼續MediaPlayer的播放,轉到Started狀態,暫停狀態時可以調用seekTo()方法,這是不會改變狀態的。

Stop狀態:Started或者Paused狀態下均可調用stop()停止MediaPlayer,而處于Stop狀態的MediaPlayer要想重新播放,需要通過prepareAsync()和prepare()回到先前的Prepared狀態重新開始才可以。

PlaybackCompleted狀態:文件正常播放完畢,而又沒有設置循環播放的話就進入該狀態,并會觸發OnCompletionListener的onCompletion()方法。此時可以調用start()方法重新從頭播放文件,也可以stop()停止MediaPlayer,或者也可以seekTo()來重新定位播放位置。

Error狀態:如果由于某種原因MediaPlayer出現了錯誤,會觸發OnErrorListener.onError()事件,此時MediaPlayer即進入Error狀態,及時捕捉并妥善處理這些錯誤是很重要的,可以幫助我們及時釋放相關的軟硬件資源,也可以改善用戶體驗。通過setOnErrorListener(android.media.MediaPlayer.OnErrorListener)可以設置該監聽器。如果MediaPlayer進入了Error狀態,可以通過調用reset()來恢復,使得MediaPlayer重新返回到Idle狀態。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容