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

xiaoxiao2021-02-28  23

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()方法中去执行。

转自:https://blog.csdn.net/madreain/article/details/52143787

转载请注明原文地址: https://www.6miu.com/read-2450340.html

最新回复(0)