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;
}

總結就到這裏。

 

 

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