一、概述
案例:实现一个视频预缓存的需求
原理:
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;