首先推荐一个讲解WebViewClient自带控制缓存的博客:http://blog.csdn.net/a345017062/article/details/8573689
WebViewClient自带缓存设置是这样的:LOAD_CACHE_ONLY只加载缓存; LOAD_CACHE_ELSE_NETWORK 无论是否过期,都加载缓存。本地没有缓存时再从网络加载;LOAD_DEFAULT根据web端控制;LOAD_NO_CACHE不用缓存;
那么WebView缓存的设置,通常我们会选择这样做:如果有网LOAD_DEFAULT;反之 LOAD_CACHE_ELSE_NETWORK;言外之意要么根据Web端去控制,要么就只加载缓存,网络没机会加载。是不是感觉缓存机制不是很完美?
如果我们想完善一下,这样:有缓存就先加载缓存,再加载网络,替换缓存文件,无缓存直接加载网络,无网异常机制。当然这只是一种方案,其他更好的方案欢迎交流。
想这样,再打算依赖Api自带缓存设置就有点捉襟见肘了,那么我们自己来实现吧
WebViewClient 自带了一个拦截请求的方法:shouldInterceptRequest,返回拦截到的资源。但是存在api版本限制,低版本无法通过该方法实现请求拦截。
我们是否可以参考这个拦截思路,发起请求获取网页内容并将其转换成我们的本地存储,再去用WebView加载这个本地存储呢?
答案是肯定的!
WebView的load方法有多种,通常我们没有特殊需求会用WebView.loadUrl(String)。另外还有加载本地页面、本地资源的方法,请看:
[代码]java代码:
loadData(String html,String mimeType,String encoding) |
[代码]java代码:
loadDataWithBaseURL(String baseUrl, String data,String mimeType, String encoding, String historyUrl); |
第一个方法需要的是整个Html页面,我们页面简单的话,可以全部down下来然后作为本地缓存页面加载;but!谁敢保证我们日常页面很简单?既然选择优化,那就把活干的全面一点吧,我们来看第二个方法:url、数据、类型、编码、history;这里不考虑页面前进后退等问题,那是另一种实现。详细Api就不细说了。根据这个方法我们反推一下加载缓存页面的实现思路:
String 类型的Data使我们要加载的内容,内容来源于网页,网页是不是可以通过网络请求获取?再提供页面一些关键参数,最终完成缓存加载路线,齐活!
缓存思路:开启子线程>使用Http协议>获取网页资源>存储到指定路径>构造String类型>使用load方法加载缓存
下面看网络请求获取网页,这里我们使用HttpURLConnection,已知url:
[代码]java代码:
InputStream inputStream = null ; HttpURLConnection httpConnection = null ; try { URL url = new URL(url); if (url == null ) { return null ; } httpConnection = (HttpURLConnection) url .openConnection(); if (httpConnection == null ) { return null ; } httpConnection.setConnectTimeout( 500 ); httpConnection.setReadTimeout( 500 ); int responseCode = httpConnection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { inputStream = httpConnection.getInputStream(); } if (inputStream == null ) return null ; byte [] inputDatas = readBytes(inputStream); //将输入流转换成字节数组存储,这里不再叙述 return inputDatas ; } catch (Exception e) { e.printStackTrace(); return null ; } finally { if (inputStream != null ) //关闭资源 try { inputStream.close(); } catch (IOException e1) { e1.printStackTrace(); } if (httpConnection != null ) { httpConnection.disconnect(); } //将我们获取的资源进行本地序列化,这里不贴出实现方案 } |
至此,我们有了网页内容,剩下的minyType以及encoding最好还是从Http请求头中获取,HttpURLConnection.getContentType(),解析方案各种斟酌,见仁见智。
好了,缓存有了,我们调上面那个load方法试试看:loadDataWithBaseURL(url, new String(byte[]data), mimeType, encoding, null);
哦了。
剩下的就是策略问题了:缓存加载完了,再加载网络还远么?为了避免WebView自带的缓存策略影响我们缓存的更新,我们不使用loadUrl,还用上面那个HttpUrlConnection去加载页面,来完成我们缓存的更新动作,此时新的缓存就是我们加载完网络页面之后的新内容,可以将其作为网络内容看待。
而整体控制缓存与网络的实现可以是这样的:
无网,加载缓存,无缓存,失败;
有网,加载缓存,同时获取网络页面更新缓存,加载新缓存更新页面显示,旧缓存没有,新缓存也没有,失败。
这么做的好处是什么?打个比方,WebView页面通常属于强展示弱交互页面,而这些页面的展示优先程度就会比较高,页面内容的变化也会比较频繁。通常按默认的处理会是这样:加载网络页面,而网络又经常特别慢,页面就会经常等待很久,而我们有缓存了,但是过期了,那就等吧。
我们按上面的方案处理了之后,可以变成这样:不考虑缓存有效期,快速展示本地缓存页面,这个过程中无论网络如何,新缓存是否更新完成,我们可爱的用户都已经看到了页面,当网络加载完成,页面刷新。完美