Android關於VideoView的一些思考和總結
最近在做一期有關於視訊的專案開發。因為專案週期比較緊,而且自己以前也沒有對於視訊相關的經驗積累。所以在開發的時候遇到了問題,自己嘗試解決並記錄下來。(PS:視訊都是下載完再進行播放類似於微信朋友圈的視訊功能,播放元件用的是分裝的原生的VideoView)
一、視訊播放時會有短暫的黑屏時間:
- 產生原因:視訊檔案載入到記憶體中是需要時間,這個時間可能匯入VideoView全黑。
- 解決方法(1):給VideoView新增
MediaPlayer.OnPreparedListener
監聽事件,在其onPrepared(MediaPlayer mp)
方法回撥中播放視訊這個時候視訊已經完成了載入。(PS:此方法在有些情況下使用有些問題,因為播放視訊的時候MediaPlayer.OnPreparedListener
- 解決方法(2):笨方法,同時也是最管用的方法。在VideoView執行
start()
方法時視訊的預覽圖不是立即消失而是延遲幾百毫秒之後消失,這是視訊已經載入完成,當然體驗上有些不好。
二、在進入有VideoView介面的Activity時會出現閃黑屏的情況(如論視訊是否播放):
產生原因:不祥(自己沒有找到認為正確的答案)
解決方法:在整個介面建立之前新增這行程式碼
getWindow().setFormat(PixelFormat.TRANSLUCENT);
三、當前介面有視訊播放時進入其他介面,然後跳轉回來後VideoView展示全黑(按home鍵再次進入app也會有同樣的問題):
產生原因:VideoView被回收掉,而自己沒做VideoView的狀態儲存處理
解決方法:在VideoView所在的Activity或者Fragment的生命週期中處理VideoView視訊播放和暫停。
四、在類似微信列表頁視訊播放點選大圖播放時列表的VideoView回出現在大圖的VideoView之上(PS:如果列表的VideoView和大圖播放的VideoView不是同一個):
- 產生原因:SurfaceView預設會出現在最頂部的。
- 解決方法: 小圖播放時要隱藏掉(GONE而不是INVISIBLE)。
五、VideoView巢狀ViewPager使用時,在滑動ViewPager過程中視VideoView會出現透明(此時VideoView是自動播放)(PS:此時Activity的主題為
android:theme="@style/Transparent"
產生原因:ViewPager在執行
public void onPageSelected(int position)
方法時當前介面還是展示兩個View。即下一個View並沒有完全漏出來。解決方法:定義ViewPager的
ViewPager.OnPageChangeListener
介面,覆蓋public void onPageScrolled(int postion, float v, int i)
方法,監聽讓下一個介面完全展現出來之後在執行public void onPageSelected(int position)
方法。然後再在方法裡處理下一個視訊的播放以及上一個的停止。
六、使用VideoView造成介面其他組價焦點產生“遺失”:
現象:在ViewTreeObserver.addOnPreDrawListener新增新的OnPreDrawListener的onPreDraw多次執行。
解決辦法(1):使用SurfaceView+MediaPlayer自定義播放器
解決辦法(2):對VideoView的建構函式中的焦點處理的方法進行反處理,即在VideoView子類(這裡應該就是自己寫的自定義VideoView其繼承與VideoView)的構造方法中進行反處理。
//VideoView原始碼
public class VideoView extends SurfaceView
implements MediaPlayerControl, SubtitleController.Anchor {
private String TAG = "VideoView";
/*其他程式碼省略*/
//每個建構函式中都執行initVideoView
public VideoView(Context context) {
super(context);
initVideoView();
}
public VideoView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
initVideoView();
}
public VideoView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public VideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initVideoView();
}
/*其他程式碼省略*/
private void initVideoView() {
mVideoWidth = 0;
mVideoHeight = 0;
getHolder().addCallback(mSHCallback);
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//start 下邊3行程式碼是對焦點進行的處理,以及自己所謂的反處理
setFocusable(true); //子類setFocusable(false);
setFocusableInTouchMode(true); //子類setFocusableInTouchMode(false);
requestFocus(); //子類clearFocus();
//end
mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();
mCurrentState = STATE_IDLE;
mTargetState = STATE_IDLE;
}
/*其他程式碼省略*/
}
七、在VideoView的
MediaPlayer.OnCompletionListener
回撥監聽public void onCompletion(MediaPlayer mp)
方法裡進行視訊的播放(PS:這個指的是視訊的迴圈播放),在有些手機上不能正常重新播放。產生原因:在部分手機上VideoView的
MediaPlayer.OnCompletionListener
回撥監聽public void onCompletion(MediaPlayer mp)
方法裡此時`VideoView.isPlaying()
的值還是為true。解決辦法:在VideoView的
MediaPlayer.OnCompletionListener
回撥監聽public void onCompletion(MediaPlayer mp)
方法裡對`VideoView.start()
方法進行延遲播放。一般這個時間不會太長,幾百毫秒就可以。視覺感官上也還好。
以上是自己在僅僅兩週開發使用VideoView開發視訊有關專案中遇到的問題,和一些不是很成熟的解決方案。