• Android webview通过http get下载文件下载两次的问题及解决方法


    一、现象

       一般通过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

  • 相关阅读:
    linq 读取xml
    c# 定时器 自动执行
    如何在一个人输入框中只输入数字
    如何去掉滚动条,
    如何计算任意值之间的随机数呢
    【P2387】魔法森林(SPFA非正解)
    【Luogu】P3203弹飞绵羊(分块)
    【Luogu】P3396哈希冲突(根号算法)
    【Luogu】P2801教主的魔法(分块)
    【Luogu】P3155叶子的染色(树形DP)
  • 原文地址:https://www.cnblogs.com/jiangz/p/3722476.html
Copyright © 2020-2023  润新知