WebView自定义缓存路径

首先推荐一个讲解WebViewClient自带控制缓存的博客:http://blog.csdn.net/a345017062/article/details/8573689

WebViewClient自带缓存

LOAD_CACHE_ONLY:只加载缓存;
LOAD_CACHE_ELSE_NETWORK: 无论是否过期,都加载缓存。本地没有缓存时再从网络加载;LOAD_DEFAULT:根据web端控制,实际也是由请求头读取到的参数控制;
LOAD_NO_CACHE:不使用缓存;

我们的默认做法

如果有网LOAD_DEFAULT;反之 LOAD_CACHE_ELSE_NETWORK;言外之意要么根据Web端去控制,要么就只加载缓存,网络没机会加载。是不是感觉缓存机制不是很完美?

如果想这样

有缓存就先加载缓存,同时加载网络,网络成功后替换缓存文件,无缓存直接加载网络,无网异常机制。当然这只是多种方案中的一种,其他更好的方案欢迎交流。

想这样,再打算依赖Api自带缓存设置就有点捉襟见肘了,那么我们自己来实现吧

WebViewClient 自带了一个拦截请求的方法:shouldInterceptRequest,返回拦截到的资源。但是存在api版本限制,低版本无法通过该方法实现请求拦截。
我们是否可以参考这个拦截思路,发起请求获取网页内容并将其转换成我们的本地存储,再去用WebView加载这个本地存储呢?

答案是肯定的!

WebView的load方法有多种,通常我们没有特殊需求会用WebView.loadUrl(String)。除此之外还有加载本地页面、本地资源的方法,请看:

loadData(String html,String mimeType,String encoding)
loadDataWithBaseURL(String baseUrl, String data,String mimeType, String encoding, String historyUrl);

第一个方法需要的是整个Html页面,我们页面简单的话,可以全部down下来然后作为本地缓存页面加载;
but!谁敢保证我们日常页面很简单?既然选择优化,那就把活干的全面一点吧。

我们来看第二个方法:url、数据、类型、编码、history;假设不考虑页面前进后退等问题。详细Api就不细说了。根据这个方法我们反推一下加载缓存页面的实现思路:

String 类型的Data使我们要加载的内容,内容来源于网页,网页是不是可以通过网络请求获取?再提供页面一些关键参数,最终完成缓存加载路线,齐活!

缓存思路

开启子线程>使用Http协议>获取网页资源>存储到指定路径>构造String类型>使用load方法加载缓存

下面看网络请求获取网页,这里我们使用HttpURLConnection,当然其他网络框架也可以。
已知url,看实现:

    private void loadHtmlPage(String url){

        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); //将输入流转换成字节数组存储,readBytes方法不再赘述
            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去加载页面,来完成我们缓存的更新动作,此时新的缓存就是我们加载完网络页面之后的新内容,可以将其作为网络内容看待。

整体控制缓存与网络的实现可以是这样的:

1.无网,加载缓存,无缓存,失败;
2.有网,加载缓存,同时获取网络页面更新缓存,加载新缓存更新页面显示,旧缓存没有,新缓存也没有,失败。
这么做的好处是什么?打个比方,WebView页面通常用于强展示弱交互页面,而这些页面的展示优先程度就会比较高,页面内容的变化也会比较频繁。通常按默认的处理会是这样:加载网络页面,而网络又经常特别慢,页面就会经常等待很久,而我们有缓存了,但是过期了,那就等吧。

我们按上面的方案处理了之后,可以变成这样:不考虑缓存有效期或我们自己设定有效期,快速展示本地缓存页面,这个过程中无论网络如何,新缓存是否更新完成,我们可爱的用户都已经看到了页面,当网络加载完成,页面刷新。完美

猜你喜欢

转载自blog.csdn.net/tianbo_zhang/article/details/79010339