android: ViewPager+Fragment播放视频+全屏/小屏+虚拟键问题的总结

由于产品给项目中添加了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;
    }

    List<Fragment> fragments = 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;
}

总结就到这里。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章