由于产品给项目中添加了ViewPager+Fragment 播放视频的需求,我便开始可挖坑埋坑之旅。在开发中真所谓是感慨良多呀,在此总结下开发需要注意的点,踩过的坑,以备后用。
1.android 阿里播放器文档的问题。
由于将视频的存储位置要迁移到阿里考虑到视频也有加密的功能,所以我们选用阿里的播放器。阿里播放器中的文档缺少添加相应的依赖地址,所以害我找了半天代码的问题,最终在官方demo中找到那个缺少的地址。
如下是在anroid 播放器 3.4.8版本要添加的依赖。
---------------------------------
api(name: 'AlivcPlayer-3.4.8', ext: 'aar')
api(name: 'AlivcReporter-1.2', ext: 'aar')
api(name: 'AliyunVodPlayer-3.4.8', ext: 'aar')
implementation 'com.aliyun.dpa:oss-android-sdk:2.4.5'//少了这个
implementation project(':aliyunZxing')//自己导入
----------------------------------
2.是否使用懒加载问题。
原本每个Fragment中就添加有WebView ,如果再添加上播放器这种消耗性能的控件会更令人担忧,所以刚开始还是选择了懒加载去加载fragment。虽说最终用懒加载也实现了大部分功能,但是会有几个问题:1.用户体验不是很好,我们的fragment的数量是根据考点的多少来动态生成的,每次都是滑倒才加载,这样效果很不好。2.由于是懒加载会导致在viewpager的滑动监听和setUserVisibleHint方法中拿到的当前位置出现不对应的问题(通过EventBus发送事件,通过Fragment管理器拿到Fragment等),这样会到导致拿到错误的当前Fragment,以致于视频可能会出现同时播放两个的问题,去掉懒加载拿到当前Fragment的就简单了,就不会有这样的问题。
3.setUserVisibleHint的用法。
在 setUserVisibleHint(boolean isVisibleToUser)方法中通过判断 getUserVisibleHint() 可判断此时Fragment可见,可在这里进行播放器自定状态处理。
当 isVisibleTouser = false 并且 isVisible() = true 时说明该fragment是刚刚被划过去的,在这里也可以根据实际业务需求做自己想做的处理。
4.视频会在这个视频上残留上个视频的残影的问题。
使用的阿里的视频播放器,在常见问题中提到这个问题,解决办法是让播放器stop然后再reset来处理(个人认为这种情况用于统一播放器而言),我们的是不同的fragment中都有不同的播放器不合适。也有提到将播放器中的SurfaceView 换成TextTrueView 来替代,那么我们可百度下 SurfaceView 替换为TextTrueVew 来解决,这种方案真的解决了残影问题,也不是很麻烦。
5.全屏和小屏的问题。
(1)实现思路:
这个参考网上例子就是再Fragment 外层的Activity 中放一个全屏视频的容器,点击全屏的时候将小屏中的播放器View 放到 全屏容器中,点击小屏再将播放器View 放到 小屏中即可。具体参考链接:https://blog.csdn.net/u010072711/article/details/51517170 参考了其中的第五种方式。
(2)播放器内部对全屏小屏的影响。
因为在播放器内部实现了对手机屏幕选中的监听判断,通过手机旋转的角度来判断横竖屏,只要手机有相应的角度变化,屏幕就会旋转,
所以导致了我在mainfest.xml中怎么修改清单配置都不能去掉自动旋转。将播放View中的旋转监听去掉就好了。
(3)在全屏的时候,来回滑动Fragment 会出现两个播放器都在横屏播放,无法控制。这个问题原因在与:因为ViewPager+Fragment 播放视频,在Fragmenet 内部监听onConfigurationChanged(Configuration configuration) 然后对播放器Veiw 进行全屏和小屏的操作,那么在ViewPager中我不用Fragmenet的懒加载,就是默认加载前后各一个Fragment。当屏幕方向变化的时候多个fragment都会收到这个通知,将小屏中的播放View 放到Activity的 视频Container中,那么就会导致横屏的时候全屏有多个播放器对象,所以就无法正确的控制播放器了。那么我的解决方案是在Activity 中判断并且拿到当前的Fragment:mCurrentFragment,在Activity 的onConfigurationChanged(Configuration configuration) 中调用mCurrentFragment 的处理全屏小屏的逻辑就可以了。如何拿到当前Fragment 请看第七条。
6.虚拟键导致4.4手机全屏后手机屏幕部分黑屏的问题,以及高版本的显示留出多余黑色空间的问题。
这里主要是关于window的Flag相关的问题,网上找了好多大部分都不起作用,只有一篇文章起了作用(具体地址找不到了。。。):具体代码如下:
/** * 全屏时,window的处理(可解决虚拟键问题) */ private void dealWithFullScreen() { WindowManager.LayoutParams attrs = mActivity.getWindow().getAttributes(); attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; mActivity.getWindow().setAttributes(attrs); mActivity.getWindow().addFlags( WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); } /** * 小屏时,window的处理(可解决虚拟键问题) */ private void dealWithSmallScreen() { WindowManager.LayoutParams attrs = mActivity.getWindow().getAttributes(); attrs.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN); mActivity.getWindow().setAttributes(attrs); mActivity.getWindow().clearFlags( WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); }
7.在viewpager 所在Activity中拿到当前显示Fragment。
(1)在滑动监听中调用,可拿到当前Fragment 。
其中 mTestItemsIdList是项目中的考点id集合,根据id来判断当前的fragment 。
/** * 在滑动之后,给当前位置的Fragment mCurrentFragment 赋值 * * @param position 当前位置,onPageSelected(int position)中的positon */ private void getCurrentFragment(int position) { if (mTestItemsIdList == null) { return; } int itemSize = mTestItemsIdList.size(); if (itemSize == 0 || position >= itemSize) { return; } int testItemId = mTestItemsIdList.get(position); FragmentManager fm = getSupportFragmentManager(); if (fm == null) { return; } Listfragments = fm.getFragments(); if (fragments == null) { return; } int fragmentSize = fragments.size(); for (int i = 0; i < fragmentSize; i++) { Fragment fragment = fragments.get(i); if (fragment == null) { continue; } if (fragment instanceof ExaminationPointDetailFragment) { ExaminationPointDetailFragment detailFragment = (ExaminationPointDetailFragment) fragment; int tempTestItemId = detailFragment.getTestItemId(); if (tempTestItemId == testItemId) { mCurrentFragment = detailFragment; break; } } } }
(2)在第一个可见的fragment的显示的时候并没有滑动viewpager,所以要在适配器的getItem方法中通过变量标记的方法来确定当前Fragment。
@Override public ExaminationPointDetailFragment getItem(int position) { ExaminationPointDetailFragment fragment = ExaminationPointDetailFragment.newInstance(position, mDefaultPosition, db, mSize, mPackageId); //mIsFirstVisible 成员变量,初始值为true.拿到当前Fragment之后赋值为false. if (mIsFirstVisible) { mCurrentFragment = fragment; } mIsFirstVisible = false; return fragment; }
总结就到这里。