由於產品給項目中添加了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; }
總結就到這裏。