您的位置:首页 > 移动开发

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进行编码,否则会报错

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加载时本地有的图片就加载本地,本地没有则加载网络图片。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息