Android 不得不说的VideoView的一些坑及其解决方案

最近公司做动态展示新添加了视频,然后去摸索了一些视频的相关问题,最终选择了Android原生的VideoView。开发中遇到了一些坑给大家分享出来,不得不说很坑,希望给大家做视频播放做一个参考:先总结如下:

VideoView的问题及其解决方案:

1.视频播放时会有短暂的黑屏时间: 
产生原因:视频文件加载到内存中是需要时间,这个时间可能导入VideoView全黑。

解决方法(1):给VideoView添加MediaPlayer.OnPreparedListener 监听事件,在其onPrepared(MediaPlayer mp) 方法回调中播放视频这个时候视频已经完成了加载。(PS:此方法在有些情况下使用有些问题,因为播放视频的时候MediaPlayer.OnPreparedListener 监听不到回调,要先用此方法解决最本质问题得好好研究一下源码)。 
解决方法(2):笨方法,同时也是最直接的方法。在VideoView执行start() 方法时视频的预览图不是立即消失而是延迟几百毫秒之后消失,这是视频已经加载完成,当然体验上有些不好。

  1. new Thread( new Runnable() {
  2. @Override
  3. public void run () {
  4. SystemClock.sleep( 200);
  5. runOnUiThread( new Runnable() {
  6. @Override
  7. public void run () {
  8. //执行让预览图消失的方法
  9. }
  10. });
  11. }
  12. }).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)的构造方法中进行反处理。

  1. 自定义的VideoView
  2. public class VideoView extends SurfaceView
  3. implements MediaPlayerControl , SubtitleController . Anchor {
  4. private String TAG = "VideoView";
  5. /*其他代码省略*/
  6. //每个构造函数中都执行initVideoView
  7. public VideoView (Context context) {
  8. super(context);
  9. initVideoView();
  10. }
  11. public VideoView (Context context, AttributeSet attrs) {
  12. this(context, attrs, 0);
  13. initVideoView();
  14. }
  15. public VideoView(Context context, AttributeSet attrs, int defStyleAttr) {
  16. this(context, attrs, defStyleAttr, 0);
  17. }
  18. public VideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
  19. super(context, attrs, defStyleAttr, defStyleRes);
  20. initVideoView();
  21. }
  22. /*其他代码省略*/
  23. private void initVideoView () {
  24. mVideoWidth = 0;
  25. mVideoHeight = 0;
  26. getHolder().addCallback(mSHCallback);
  27. getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  28. //start 下边3行代码是对焦点进行的处理,以及自己所谓的反处理
  29. setFocusable( true); //子类setFocusable(false);
  30. setFocusableInTouchMode( true); //子类setFocusableInTouchMode(false);
  31. requestFocus(); //子类clearFocus();
  32. //end
  33. mPendingSubtitleTracks = new Vector>();
  34. mCurrentState = STATE_IDLE;
  35. mTargetState = STATE_IDLE;
  36. }
  37. /*其他代码省略*/
  38. }

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的布局参数

  1. //首先取得video的宽和高
  2. int vWidth = player.getVideoWidth();
  3. int vHeight = player.getVideoHeight();
  4. if (vWidth > video_view.getWidth() || vHeight > video_view.getHeight()) {
  5. //如果video的宽或者高超出了当前屏幕的大小,则要进行缩放
  6. float wRatio = ( float) vWidth / ( float) video_view.getWidth();
  7. float hRatio = ( float) vHeight / ( float) video_view.getHeight();
  8. //选择大的一个进行缩放
  9. float ratio = Math. max(wRatio, hRatio);
  10. vWidth = ( int) Math. ceil(( float) vWidth / ratio);
  11. vHeight = ( int) Math. ceil(( float) vHeight / ratio);
  12. //设置surfaceView的布局参数
  13. video_view.setLayoutParams( new LinearLayout.LayoutParams(vWidth, vHeight));
  14. //然后开始播放视频
  15. player.start();
  16. }

这个写在setOnPreparedListener的onPrepared()方法中去执行。


更多相关文章

  1. android下自定义字体的使用方法
  2. 伦敦开发者构建了一个基于 Android 的坦克 [视频]
  3. android 仿ios数字密码解锁界面的实例
  4. 自定义实现类似android主界面的滑屏换屏控件
  5. [Android Studio系列(三)]Android Studio 编译、同步慢的解决方
  6. Android界面设计基础:控件焦点4个步骤
  7. Android开发——纯JAVA代码方式界面设计
  8. Android界面导航之拖放框架(Drag and Drop)

随机推荐

  1. android 动态添加控件控制属性问题
  2. Android 真机调试
  3. [Android]再简单解释一下androidtest包下
  4. Android 读取配置文件的内容
  5. android 使用反射机制获取工程中的图片
  6. 文件上传
  7. 编译android内核源码
  8. Android4.4 5.0沉浸式状态栏
  9. SurfaceView + SurfaceHolder 入门
  10. android中Bitmap图像处理 修改图片大小以