一、现象

一般通过Android webview进行下载文件的方法是

1.重写DownloadListener的onDownloadStart方法,在onDownloadStart方法中弹出对话框提示用户有新的文件需要下载

2.用户点击确定之后,通过http get下载文件

由于Android webview的实现,以上的下载文件步骤涉及到了两次get的操作。第一次是用户在webview中点击下载链接时,webview自动发送http get请求,这个时候服务器除了将文件信息发送过来之外,会同时将文件的内容发送给webview。第二次是在步骤2,由自己设计的程序发起的。

为了验证如上结论,我在Android 4.4系统中的自带浏览器通过访问并下载这个测试链接,并用wireshark进行抓包查看结果。通过如下三张图,我觉得可以验证同一份文件确实被传了两次。因为两个不同http get请求之后都可以看到服务器向客户端发送的连续的TCP数据包。

二、解决方法

针对这个问题,我觉得比较完美的解决办法是webview在进行get的时候能够缓存相应的文件内容,并且开放相应的接口给应用进行缓存的读取。但是我并没有发现相应的api。

于是便有了如下的解决办法:在webview加载url之前,通过链接中的一些特定字段发现进行下载操作。然后通过http head请求获取文件名和大小等相关信息。由于http head只是请求文件相关信息,所以服务器只是通过http response将文件信息返回而不通过tcp发送文件具体内容。

2.1 实现代码

在继承自WebViewClient的类的shouldOverrideUrlLoading方法中检查链接类型,并通过http head获取文件大小,名称信息。在以下代码基础上需要增加合适的获取文件名称代码和handler的代码。

		if (url.contains("可能会进行下载的链接字段")) {
new Thread() {
public void run() {
HttpHead httpGet = new HttpHead(mUrl);
boolean success = true;
String filename="";
Integer fileLength=100;
try {
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, 8000);
HttpConnectionParams.setSoTimeout(httpParameters, 8000);
DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
//需要的话可能得增加cookie
HttpResponse httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode() == 200) {                   //如果文件名保存在Content-Disposition中,并且用的是gb2312编码方式可以参考这段代码
String nameString=httpResponse.getFirstHeader("Content-Disposition").getValue();
char [] nameChar=new char[nameString.length()];
byte [] nameBytes=new byte[nameString.length()];
nameString.getChars(0, nameString.length(), nameChar, 0);
for (int i = 0; i < nameChar.length; i++) {
nameBytes[i]=(byte)nameChar[i];
}
filename=EncodingUtils.getString(nameBytes, "gb2312");
Log.d(TAG, "file name is "+filename); String contentLength=httpResponse.getFirstHeader("Content-Length").getValue();
fileLength=Integer.parseInt(contentLength);
success=true;
}else {
success=false;
}
} catch (Exception e) {
success = false;
e.printStackTrace();
} Message msg = Message.obtain();
if(success) {
msg.what = GET_FILE_INFO_FINISHED;
Bundle mBundle=new Bundle();
mBundle.putString("fileName", filename);
mBundle.putInt("fileLength", fileLength);
msg.setData(mBundle);
}
else {
msg.what = GET_FILE_INFO_FAILED;
}
mHandler.sendMessage(msg);
}
}.start();
}else {
view.loadUrl(url);
}

2.2 适用情况

在Android 4.4中,根据网页的特点,可能会出现点击下载链接,而shouldOverrideUrlLoading不被调用的情况,这时2.1中方法则失效了。不过对于4.4之前的系统应该是适用的。

三、参考材料

3.1 http://stackoverflow.com/questions/11801787/webview-cant-download-file-without-requesting-it-twice

3.2 http://stackoverflow.com/questions/12535414/is-setdownloadlistener-ondownloadstart-called-after-the-webview-already-gets-the

Android webview通过http get下载文件下载两次的问题及解决方法的更多相关文章

  1. spring定时任务执行两次的原因与解决方法

    spring定时任务,本地执行一次,放到服务器上后,每次执行时会执行两次,原因及解决办法. http://blog.csdn.net/yaobengen/article/details/7031266 ...

  2. axios发送两次请求原因及解决方法

    axios发送两次请求原因及解决方法 最近Vue项目中使用axios组件,在页面交互中发现axios会发送两次请求,一种请求方式为OPTIONS,另外一种为自己设置的. 如图: 什么是CORS通信? ...

  3. 关于Excel 2016 总要点击两次才能打开的解决方法

    1.快捷键:win+r,输入:regedit2.定位到如下项目“HKEY_CLASSES_ROOT\Excel.Sheet.12\shell\Open\command”:3.编辑原有的内容,在最后添加 ...

  4. 最新Android 出现Please ensure that adb is correctly located at问题的解决方法

    最近经常遇到下面的问题 遇到问题描述: 运行android程序控制台输出: [2013-07-23 17:28:06 - ] The connection to adb is down, and a  ...

  5. 【我的Android进阶之旅】Android调用JNI出错 java.lang.UnsatisfiedLinkError: No implementation found for的解决方法

    错误描述 今天使用第三方的so库时候,调用JNI方法时出现了错误.报错如下所示: 11-01 16:39:20.979 4669-4669/com.netease.xtc.cloudmusic E/a ...

  6. .NET下载文件报错System.UnauthorizedAccessException的解决方法

    假设VS代码对应路径为E:\Projects\Web1,在VS用“发布Web”的方式发布后的路径为E:\Site\Web1.在IIS新建2个站点,站点A指向E:\Projects\Web1,站点B指向 ...

  7. 9.png(9位图)在android中作为background使用导致居中属性不起作用的解决方法

    在使用到9.png的布局上面添加 android:padding="0dip" 比如 <LinearLayout            android:layout_widt ...

  8. eclipse:运行 Android 项目时出现 “Unable to execute dex: Multiple dex files define” 解决方法

    android 项目在eclipse 出现Unable to execute dex: Multiple dex files define Conversion to Dalvik format fa ...

  9. [Android开发常见问题-11] Unable to execute dex: Multiple dex files define 解决方法

    最近在开发一个工程,其中用到了一个开源的库项目Android-ViewPagerIndicator. 这个项目是作为一个库出现的,如下图: 这个项目中包含了android-support-v4.jar ...

随机推荐

  1. Autodesk的照片建模云服务—Autodesk ReCap 360 photo

    现实捕捉技术方兴未艾,简单的讲现实捕捉技术就是把现实中的现状信息数字化到计算机中以便做进一步的处理.对于不同的应用目的会有不同的捕捉设备,工程或传媒娱乐行业中经常用到的肯定就是三维模型了.那如何得到三 ...

  2. [Android]仿新版QQ的tab下面拖拽标记为已读的效果

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4182929.html 可拖拽的红点,(仿新版QQ,tab下面拖 ...

  3. 微信小程序管理后台介绍

    微信小程序的管理后台,每次进入都需要扫码,还是特别不爽,现在微信小程序还没正式发布,很多人都还没看到管理后台,这里抢先发布出来 ------------------------------------ ...

  4. iOS开发之多媒体API (转载)

    视频格式可以分为适合本地播放的本地影像视频和适合在网络中播放的网络流媒体影像视频两大类.尽管后者在播放的稳定性和播放画面质量上可能没有前者 优秀,但网络流媒体影像视频的广泛传播性使之正被广泛应用于视频 ...

  5. Redis存储Tomcat集群的Session

    Redis存储Tomcat集群的Session 如何 做到把新开发的代码推送到到生产系统中部署,生产系统要能够零宕机.对使用用户零影响. 设想 是使用集群来搞定,通过通知负载均衡Nginx,取下集群中 ...

  6. 看苹果官方API

    command+shift+0会出现如下图 然后输入你想找的API 记得找带Reference这种标记的文档

  7. 禁止uiscrollview垂直方向滚动,只允许水平方向滚动;或只允许垂直方向滚动

    禁止UIScrollView垂直方向滚动,只允许水平方向滚动 scrollview.contentSize =  CGSizeMake(你要的长度, 0); 禁止UIScrollView水平方向滚动, ...

  8. winform ListView应用之分组、重绘图标、网格线 (c# .net winform)

    最近在winform应用中需要用到可分组的数据列表功能,DataGridView默认没有提供分组的功能,而OutlookGrid(http://www.codeproject.com/KB/grid/ ...

  9. 坑!坑!坑!防不胜防的unsigned int的运算

    我很早之前就知道,unsigned int与int运算的时候,int会被转化为unsigned int来进行运算.一直觉得定这条规则的人是极度反人类的,虽说unsigned int可以表示更大的正值, ...

  10. CSS3 background-size属性

    请复制粘贴,图片请自带 <!DOCTYPE html > <html > <head> <meta charset="utf-8"> ...