視頻在滑動列表中的異步緩存和播放,轉自大量高質量遊戲應用源碼的衆籌論壇php
http://www.zccode.com/forum.php?mod=viewthread&tid=679&extra=git
最近在Github上看到VideoPlayerManager這麼一個項目,目的在是ListView和RecyclerView中播放小視頻,模仿了Instagram中滑動到可見視頻項時開始播放該視頻,滑動至不可見時中止視頻播放的功能github
可是該項目存在幾個問題:swift
快速上下滑動列表後,沒法再播放視頻,有時還會直接Crash緩存
不支持網絡視頻的異步緩存網絡
故在該項目的基礎上進行了優化,而且支持網絡視頻的異步緩存框架
視頻的緩存其實跟圖片緩存大體是同樣的,如今圖片緩存框架不少,可是根本原理都是網絡下載+內存緩存+本地緩存這三大塊組成。而視頻的緩存只須要跳過內存緩存就能夠了,當發視頻文件未下載時就去下載並本地緩存,下次就直接從本地緩存讀取視頻文件信息,因此基於圖片緩存框架不難實現視頻文件的緩存功能。異步
這裏我採用了Glide來實現視頻緩存,Glide不只支持圖片緩存還支持對普通文件緩存,因此使用Glide能夠很簡單的就能實現視頻文件的緩存ide
Android原生提供了一個視頻播放控件 - VideoView,但VideoView是基於SurfaceView實現的,SurfaceView會單獨一個窗口用來繪製,它不在View hierachy中,顯示也不受View的屬性控制,不能進行平移,縮放等變換,也難以放在ListView或者ScrollView中,一些View中的特性也沒法使用。post
爲了彌補SurfaceView的不足,Android在4.0中加入了TextureView,它並無建立一個單獨的窗口用來繪製,這使得它能夠像通常的View同樣執行一些變換操做,設置透明度等,也很方便的放在其它ViewGroup中
因此要在ListView或者RecyclerView中播放視頻,咱們就須要實現基於TextureView的VideoView,實現代碼參考ViewVideo就能夠了
要實現視頻的自動播放和中止,咱們須要計算每一個item中列表中的可見比。好比當某item可見比大於70%時,則該item視爲可見的,激活視頻播放。反之視爲不可見,中止視頻播放
這裏簡單說下實現原理,主要分爲下面三步
在列表滑動時,判斷滑動方向
根據滑動方向判斷相鄰的item是否視爲可見,好比在下滑列表時,當前可見item的可見比在逐漸減少,而下一項的可見比在逐漸加大,當前item可見比低於70%時中止播放,下一項可見比大於70%時就開始播放
在快速滑動列表時,不檢測item的變化(避免卡頓);在滑動中止時,查找當前可見item中可見比最大的item,若是該item和以前可見的item不同時,則激活該item
視頻的播放主要使用了MediaPlayer,MediaPlayer的狀態圖以下所示:
state diagram
從圖中能夠看出,視頻在開始播放前須要首先經過setDataSource()進行初始化,而後經過prepare()或者prepareAsync()進行播放前準備工做,最後準備完成後經過start()操做纔開始播放視頻
其中prepare()操做是至關耗時的,這一步操做毫不應該在UI線程中調用,而prepareAsync()則是使用異步的方式調用,因此在list列表中播放視頻應該使用prepareAsync()來準備視頻
光靠prepareAsync()這一步,可不足以保證list滑動時每幀耗時不超過16ms,像setDataSource(),reset(),release()這些操做都是比較耗時的,雖然達不到引發ANR的程度,可是對於list滑動的流暢性卻影響很大
這裏我採用了將MediaPlayer的所有操做都放在一個單獨的線程中去處理,事件回調則經過ui Handler post回ui線程,這樣就能夠保證list滑動的流暢性
代碼具體的使用和詳細實現方法都已放到Github上
項目地址:VideoListPlayer
歡迎你們拍磚
原文出處:blog.waynell.com