webview加载html的离线缓存
2015-12-15 10:39
190 查看
首先知道webview自带离线缓存功能:
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,都使用缓存中的数据。
但是这都是通过直接加载一个URL来缓存的,而我的要求是加载本地的html,在html中有图片需要网络加载,html可以通过加网络请求后缓存到本地,但是其中的图片加载需要下载才能实现缓存的要求:
具体思路是通过得到HTML中的图片地址,然后下载,然后对webview更新,网上找到的资料是用js代码更新,但是测试的时候没有效果,所以我的思路是:
1.第一次加载时直接加载原html数据,其中的图片从网络加载;
2.将html代码中img标签替换为本地地址,并且将html代码缓存到本地,并且开始下载图片;
3.再次读取该网页时首先判断本地是否有该网页的html代码,有的话读取本地已经替换过img标签的html代码;
4.由于图片已经下载在本地,加载该html代码时图片就从本地加载的,从而达到缓存的效果;
代码:
第一步:第一次加载时直接加载原html数据,其中的图片从网络加载,并且开始下载图片;
这是存储及读取html代码的部分,key为文件名,用URL,但是有//符号,最好用MD5进行编码,否则会报错
然后加载时先读取本地,如果没有该文件就读取网络数据:
然后webview.loadDataWtihBaseURL对这段html加载就可以了。
第二步:将html代码中img标签替换为本地地址,并且将html代码缓存到本地,并且开始下载图片;
将从网络加载的html代码的img标签进行替换,然后保存到本地:
这里需要使用jsoup这个包,将html解析为Document,然后遍历img标签,将其中的URL保存到list中,然后替换为本地地址,注意地址前需要加
这样就可以在html代码中加载本地图片,在这里需要将这段更改后的html代码保存到本地,并开始下载:
这里我使用的是Xutils来进行下载,注意下载路径是上面标签替换的路径:
需要将上面报错图片网络地址的list传入就可以,注意http.download的参数,第四个必须为false,如果为true的话可能会将图片的名字更改,我在做的过程中就遇到了这个问题。
第三步,第四部:再次读取时所有资源都来自本地;
测试过程中还可以,但是想到一种情况,就是图片没有下载完毕,但是下次读取时因为是本地的html代码,其中的img标签已经被替换,所以本地没有,网络地址也没有,就会读取图片失败,所以我的思路就是讲图片网络地址保存在img标签的属性下,读取本地html时检验一下是否所有img标签下的图片都下载了,如果没有下载就将该标签下的src属性替换回网络地址,这样webview加载时本地有的图片就加载本地,本地没有则加载网络图片。
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,都使用缓存中的数据。
但是这都是通过直接加载一个URL来缓存的,而我的要求是加载本地的html,在html中有图片需要网络加载,html可以通过加网络请求后缓存到本地,但是其中的图片加载需要下载才能实现缓存的要求:
具体思路是通过得到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加载时本地有的图片就加载本地,本地没有则加载网络图片。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories