原生VideoView使用总结

Android 上原生的控件 VideoView 当然是做视频播放的首选,使用简单,下面介绍一下自己在项目使用过程中的一些注意点.

  1. 宽高问题.

    1. VideoView 的源码可知,不管你设置的 View 的宽高是多少, VideoView 会根据视频文件的宽高重新设置 View 的宽高,最终显示效果类似于 ImageViewFIT_CENTER.
    2. 如果想自定义宽高,做到 FIT_XY 的效果,就需要继承 VideoView 重写 onMeasure 方法.
  2. 播放和暂停/恢复.

    1. 播放调用 setVideoPath()setVideoURI() 即可, VideoView 会异步加载视频,加载完毕回调 OnPreparedListener() .如果播放本地视频,放进 raw 文件夹,如 video_guide.mp4.

       mVideoView.setVideoPath("android.resource://" + getPackageName() + "/raw/video_guide");
       mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
           @Override
           public void onPrepared(MediaPlayer mp) {
                   mp.start();
           }
         }
    2. 暂停: pause().

    3. 恢复: start().注意这里不要调用 resume().

  3. 进度条.

    1. 进度检测

      UI中一般会有一个 SeekBar 来显示当前播放进度,这里我采取是定时刷新的的办法:

      1.在 OnPreparedListener() 中设置 SeekBar 的 max 值.

       mSeekBar.setMax(mp.getDuration());

      2.通过 Handler 每秒计算 SeekBar 的位置.

       mSeekBar.setProgress(mVideoView.getCurrentPosition()).
    2. 进度条拖动,必然是通过 OnSeekBarChangeListener() 监控.

       mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
           @Override
           public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                   //建议在这里更新显示当前拖动的时间
           }
      
           @Override
           public void onStartTrackingTouch(SeekBar seekBar) {
                   //建议在这里(开始拖动时)停止倒计时
           }
      
           @Override
           public void onStopTrackingTouch(SeekBar seekBar) {
                   //建议在这里(停止拖动时)将 VideoView seekTo 当前位置.
           }
       });
      
      同时在 `OnPreparedListener()` 中, 为 `MediaPlayer` 设置 `OnSeekCompleteListener()` 来监听滑动停止.
      
          mp.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
               @Override
               public void onSeekComplete(MediaPlayer mp) {
                   //同时开始倒计时
                   mVideoView.start();
               }
           });
  4. 显示和隐藏 Loading 图.

    如果播放网络视频,难免会遇到缓冲的情况,除了视频需要切片之外,客户端还需要监听缓冲状态以显示/隐藏 Loading 图.

     mp.setOnInfoListener(new MediaPlayer.OnInfoListener() {
                     @Override
                     public boolean onInfo(MediaPlayer mp, int what, int extra) {
                         switch (what) {
                             case MediaPlayer.MEDIA_INFO_BUFFERING_START:
                                 //显示 Loading 图
                                 break;
                             case MediaPlayer.MEDIA_INFO_BUFFERING_END:
                                 //隐藏 Loading 图
                                 break;
                         }
                         return false;
                     }
                 });
  5. “无法加载此视频”的提示.

    如果是一个无法播放的视频,会弹出一个”无法播放此视频”的 Dialog. 从体验的角度来说就算无法播放也不能用这样的 Dialog 来提示,查看源码可知, 只需要为 VideoView 设置 OnErrorListener() 即可.

  6. 横竖屏切换.

    视频当然是全屏播放最好,此时就需要将 Activity 变为横屏.

    1. AndroidManifest.xml 设置当前 ActivityconfigChanges 属性.

       android:configChanges="orientation
    2. 通过代码改变当前 Activity 的横竖屏.

       //横屏activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
       //竖屏activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    3. ViewActivityonConfigurationChanged() 回调中处理横竖屏切换.

       @Override
       protected void onConfigurationChanged(Configuration newConfig) {
           super.onConfigurationChanged(newConfig);
           if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
               //横屏
           } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
               //竖屏
           }
       }
  7. 切换后台或打开新页面(即经过 ActivityonStop() 生命周期.

    因为 VideoView 继承了 SurfaceView , 在 ActivityonStop() 生命周期中会调用 surfaceDestroyed(), 此时会释放 MediaPlayer, 所以当切换后台或打开新页面回来,视频就会重头播放,暂时还没想到解决办法.

以上就是关于原生 VideoView 的简单使用, 下一步我考虑切换到 Google 的 ExoPlayer , 如果使用顺利我会继续总结.