Android 不得不說的VideoView的一些坑及其解決方案

Android 不得不說的VideoView的一些坑及其解決方案

最近公司做動態展示新添加了視頻,然後去摸索了一些視頻的相關問題,最終選擇了Android原生的VideoView。開發中遇到了一些坑給大家分享出來,不得不說很坑,希望給大家做視頻播放做一個參考:先總結如下:

VideoView的問題及其解決方案:

1.視頻播放時會有短暫的黑屏時間:
產生原因:視頻文件加載到內存中是需要時間,這個時間可能導入VideoView全黑。

解決方法(1):給VideoView添加MediaPlayer.OnPreparedListener 監聽事件,在其onPrepared(MediaPlayer mp) 方法回調中播放視頻這個時候視頻已經完成了加載。(PS:此方法在有些情況下使用有些問題,因爲播放視頻的時候MediaPlayer.OnPreparedListener 監聽不到回調,要先用此方法解決最本質問題得好好研究一下源碼)。
解決方法(2):笨方法,同時也是最直接的方法。在VideoView執行start() 方法時視頻的預覽圖不是立即消失而是延遲幾百毫秒之後消失,這是視頻已經加載完成,當然體驗上有些不好。

                        new Thread(new Runnable() {
                                @Override
                                public void run() {
                                    SystemClock.sleep(200);
                                    runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            //執行讓預覽圖消失的方法
                                        }
                                    });

                                }
                            }).start();

2.進入有VideoView界面的Activity時會出現閃黑屏的情況(如論視頻是否播放):

產生原因:不祥(本人認爲好像是窗口的問題)

解決方法:在整個界面創建之前添加這行代碼getWindow().setFormat(PixelFormat.TRANSLUCENT);
(PixelFormat.TRANSPARENT和PixelFormat.TRANSLUCENT作用差不多,都是使窗口支持透明度)

3.當前界面有視頻播放時進入其他界面(或者談起PopupWindow/分享到微信、朋朋友圈、QQ等),然後跳轉回來後VideoView展示全黑(按home鍵再次進入app也會有同樣的問題):

產生原因:VideoView被回收掉,而自己沒做VideoView的狀態保存處理

解決方法:在VideoView所在的Activity或者Fragment的生命週期中處理VideoView視頻播放和暫停。(查看VideoView的生命週期)

4.在類似微信列表頁視頻播放點擊大圖播放時列表的VideoView回出現在大圖的VideoView之上(PS:如果列表的VideoView和大圖播放的VideoView不是同一個):
產生原因:SurfaceView默認會出現在最頂部的。
解決方法: 小圖播放時要隱藏掉(GONE而不是INVISIBLE)。

5.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)方法。然後再在方法裏處理下一個視頻的播放以及上一個的停止。

6.使用VideoView造成界面其他組價焦點產生“遺失”:

現象:在ViewTreeObserver.addOnPreDrawListener添加新的OnPreDrawListener的onPreDraw多次執行。

解決辦法(1):使用SurfaceView+MediaPlayer自定義播放器

解決辦法(2):對VideoView的構造函數中的焦點處理的方法進行反處理,即在VideoView子類(這裏應該就是自己寫的自定義VideoView其繼承SurfaceView)的構造方法中進行反處理。

自定義的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;
    }
    /*其他代碼省略*/
 }

7.在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() 方法進行延遲播放。一般這個時間不會太長,幾百毫秒就可以。視覺感觀上也還好。

8.手機分辨率導致的無法播放此視頻的問題

產生原因:視頻的分辨率與手機分辨率的問題

解決辦法:設置surfaceView的佈局參數

   //首先取得video的寬和高
                    int vWidth = player.getVideoWidth();
                    int vHeight = player.getVideoHeight();

                    if (vWidth > video_view.getWidth() || vHeight > video_view.getHeight()) {
                        //如果video的寬或者高超出了當前屏幕的大小,則要進行縮放
                        float wRatio = (float) vWidth / (float) video_view.getWidth();
                        float hRatio = (float) vHeight / (float) video_view.getHeight();

                        //選擇大的一個進行縮放
                        float ratio = Math.max(wRatio, hRatio);

                        vWidth = (int) Math.ceil((float) vWidth / ratio);
                        vHeight = (int) Math.ceil((float) vHeight / ratio);

                        //設置surfaceView的佈局參數
                        video_view.setLayoutParams(new LinearLayout.LayoutParams(vWidth, vHeight));

                        //然後開始播放視頻

                        player.start();
                    }

這個寫在setOnPreparedListener的onPrepared()方法中去執行

發佈了56 篇原創文章 · 獲贊 7 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章