一、概述
案例:實現一個視頻預緩存的需求
原理:
1.本地有緩存就優先播放緩存,本地沒有緩存就從服務端拉取數據存入緩存,然后再讀取緩存播放
2.要實現1中描述的功能,a.首先要再App中新建一個代理服務 b.客戶端請求代理服務 c.代理服務收到客戶端請求,開啟一個線程A發起請求網絡服務器,d.將線程A中獲取到的數據寫入本地緩存 e.客戶端從本地緩存中讀取數據並播放。
使用到的技術及框架:
1.本例是在上一篇文章中使用到的AndroidVideoCache框架的基礎上進行改造的。
2.主要是加入了預緩存的功能PreLoadManager
源代碼下載:
二、代碼示例
1.新建一個單例類PreLoadManager
PreloadManager
2.在PreLoadManager類中定一個Map用來存儲所有的任務,其中key為url ,value為具體的任務
/** * 保存正在預加載的{@link PreloadTask} */ private LinkedHashMap<String, PreloadTask> mPreloadTasks = new LinkedHashMap<>();
3.添加一個任務到任務池子中
/** * 開始預加載 * * @param rawUrl 原始視頻地址 */ public void addPreloadTask(String rawUrl, int position) { if (isPreloaded(rawUrl)) return; PreloadTask task = new PreloadTask(); task.mRawUrl = rawUrl; task.mPosition = position; task.mCacheServer = mHttpProxyCacheServer; Log.i(TAG, "addPreloadTask: " + position); mPreloadTasks.put(rawUrl, task); if (mIsStartPreload) { //開始預加載 // Log.i(TAG,"開始預加載: " + position); task.executeOn(mExecutorService); } }
通過task.executeOn(mExecutorService)方法就立即開始執行任務,其執行的核心代碼如下所示:
/** * 開始預加載 */ private void start() { Log.i(TAG,"開始預加載:" + mPosition); HttpURLConnection connection = null; try { //獲取HttpProxyCacheServer的代理地址 String proxyUrl = mCacheServer.getProxyUrl(mRawUrl); Log.e("預加載的路徑:",proxyUrl); URL url = new URL(proxyUrl); connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(10000); connection.setReadTimeout(10000); InputStream in = new BufferedInputStream(connection.getInputStream()); int length; int read = -1; byte[] bytes = new byte[8 * 1024]; while ((length = in.read(bytes)) != -1) { read += length; //預加載完成或者取消預加載 if (mIsCanceled || read >= PreloadManager.PRELOAD_LENGTH) { Log.i(TAG,"結束預加載:" + mPosition); break; } } if (read == -1) { //這種情況一般是預加載出錯了,刪掉緩存 Log.i(TAG,"預加載失敗:" + mPosition); File cacheFile = mCacheServer.getCacheFile(mRawUrl); if (cacheFile.exists()) { cacheFile.delete(); } } } catch (Exception e) { e.printStackTrace(); Log.i(TAG,"異常結束預加載:" + mPosition+"|"+e.getMessage()+"\n"+mCacheServer.getProxyUrl(mRawUrl)); } finally { if (connection != null) { connection.disconnect(); } } }
其本質上就是模擬了一個客戶端發起了一個網絡請求,當這個網絡請求獲取到的數據包的到校>=512kb的時候立馬終止線程。客戶端線程終止后最終會調用HttpProxyCacheServerClients的finishProcessRequest()方法,同時停止真正下載數據的線程。
4.取消任務
/** * 停止所有的預緩存任務 */ public void stopAllPreloadTask() { Iterator<Map.Entry<String, PreloadTask>> iterator = mPreloadTasks.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, PreloadTask> next = iterator.next(); PreloadTask task = next.getValue(); task.cancel(); } }
5.設置預緩存的大小
/** * 預加載的大小,每個視頻預加載512KB,這個參數可根據實際情況調整 */ public static final int PRELOAD_LENGTH = 1024 * 1024 * 1;