首先知道webview自带离线缓存功能:
mWebView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
//设置 缓存模式
LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
LOAD_DEFAULT: 根据cache-control决定是否从网络上取数据。
LOAD_CACHE_NORMAL: API level 17中已经废弃, 从API level 11开始作用同LOAD_DEFAULT模式
LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。
// 开启 DOM storage API 功能
mWebView.getSettings().setDomStorageEnabled(
true
);
//开启 database storage API 功能
mWebView.getSettings().setDatabaseEnabled(
true
);
String cacheDirPath = getFilesDir().getAbsolutePath()+APP_CACAHE_DIRNAME;
//设置数据库缓存路径
mWebView.getSettings().setDatabasePath(cacheDirPath);
//设置 Application Caches 缓存目录
mWebView.getSettings().setAppCachePath(cacheDirPath);
//开启 Application Caches 功能
mWebView.getSettings().setAppCacheEnabled(
true
);
具体思路是通过得到HTML中的图片地址,然后下载,然后对webview更新,网上找到的资料是用js代码更新,但是测试的时候没有效果,所以我的思路是:
1.第一次加载时直接加载原html数据,其中的图片从网络加载;
2.将html代码中img标签替换为本地地址,并且将html代码缓存到本地,并且开始下载图片;
3.再次读取该网页时首先判断本地是否有该网页的html代码,有的话读取本地已经替换过img标签的html代码;
4.由于图片已经下载在本地,加载该html代码时图片就从本地加载的,从而达到缓存的效果;
代码:
第一步:第一次加载时直接加载原html数据,其中的图片从网络加载,并且开始下载图片;
这是存储及读取html代码的部分,key为文件名,用URL,但是有//符号,最好用MD5进行编码,否则会报错
public static void saveHtml(String key, String value, Context ctx) { key = MD5Utils.encode(key); FileOutputStream fileOutputStream = null; BufferedWriter writer = null; try { fileOutputStream = ctx.openFileOutput(key, Context.MODE_APPEND); writer = new BufferedWriter(new OutputStreamWriter(fileOutputStream)); writer.write(value); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (writer != null) { try { writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); } } } } public static String getHtml(String key, Context ctx) { key = MD5Utils.encode(key); FileInputStream fileInputStream = null; BufferedReader reader = null; StringBuilder builder = null; try { fileInputStream = ctx.openFileInput(key); reader = new BufferedReader(new InputStreamReader(fileInputStream)); builder = new StringBuilder(); String line = ""; while ((line = reader.readLine()) != null) { builder.append(line); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } if (builder != null) { return builder.toString(); } return null; }
然后加载时先读取本地,如果没有该文件就读取网络数据:
final String url = GlobalContants.TEXT_URL; responseHtml = CacheUtils.getHtml(url, getActivity()); httpUtils = new HttpUtils(); if (TextUtils.isEmpty(responseHtml)) { httpHandler = httpUtils.send(HttpRequest.HttpMethod.GET, url, new RequestCallBack<String>() { @Override public void onSuccess(ResponseInfo<String> responseInfo) { responseHtml = responseInfo.result; } @Override public void onFailure(HttpException error, String msg) { } }); }然后webview.loadDataWtihBaseURL对这段html加载就可以了。
第二步:将html代码中img标签替换为本地地址,并且将html代码缓存到本地,并且开始下载图片;
将从网络加载的html代码的img标签进行替换,然后保存到本地:
public void changeHtml(String htmlString) { imgUrls.clear(); doc = Jsoup.parse(htmlString);//将html字符串解析为Document if (doc == null) { return; } Elements es1 = doc.select("script"); if (es1 != null) { es1.remove(); } Elements es = doc.getElementsByTag("img"); for (Element e : es) { String imgUrl = e.attr("src"); imgUrls.add(imgUrl);//将图片的网络地址保存到list String imgName; int index = imgUrl.lastIndexOf("/"); imgName = imgUrl.substring(index + 1, imgUrl.length());//通过URL截取到图片名 String filePath = "file:///" + Environment.getExternalStorageDirectory() + "/test/" + imgName; e.attr("src", filePath);//替换img标签的src属性内容 } CacheUtils.saveHtml(key, doc.html(), context);//将替换img标签的html保存到本地 downloadImg(imgUrls);//开始下载图片到本地 }这里需要使用jsoup这个包,将html解析为Document,然后遍历img标签,将其中的URL保存到list中,然后替换为本地地址,注意地址前需要加
"file:///"
这样就可以在html代码中加载本地图片,在这里需要将这段更改后的html代码保存到本地,并开始下载:
这里我使用的是Xutils来进行下载,注意下载路径是上面标签替换的路径:
private void downloadImg(final List<String> imgUrls) { //若传入参数为空,则直接返回 if (imgUrls.size() == 0) return; File dir = new File(Environment.getExternalStorageState() + "/anytime/"); if (!dir.exists()) { dir.mkdir(); } for (final String urlStr : imgUrls) { if (urlStr == null) { continue; } int index = urlStr.lastIndexOf("/"); String fileName = urlStr.substring(index + 1, urlStr.length()); File file = new File(Environment.getExternalStorageDirectory() + "/anytime/" + fileName); if (file.exists()) { continue; } try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } HttpUtils http = new HttpUtils(); /*1.下在文件的地址。2.保存至本地的文件路径。*/ HttpHandler handler = http.download(urlStr, file.getPath(), false, false, new RequestCallBack<File>() { @Override public void onStart() { } @Override public void onLoading(long total, long current, boolean isUploading) { } @Override public void onSuccess(ResponseInfo<File> responseInfo) { } @Override public void onFailure(HttpException error, String msg) { } }); } }需要将上面报错图片网络地址的list传入就可以,注意http.download的参数,第四个必须为false,如果为true的话可能会将图片的名字更改,我在做的过程中就遇到了这个问题。
第三步,第四部:再次读取时所有资源都来自本地;
测试过程中还可以,但是想到一种情况,就是图片没有下载完毕,但是下次读取时因为是本地的html代码,其中的img标签已经被替换,所以本地没有,网络地址也没有,就会读取图片失败,所以我的思路就是讲图片网络地址保存在img标签的属性下,读取本地html时检验一下是否所有img标签下的图片都下载了,如果没有下载就将该标签下的src属性替换回网络地址,这样webview加载时本地有的图片就加载本地,本地没有则加载网络图片。