问题
最近项目需要一个下载的功能,所以在安卓端实现了一个普遍的下载功能模块。但Protal admin端发来信息说,怎么安卓端cal了l两次下载接口,当时以为是代码写错了,改了几次之后发现问题还在。经过网上搜索以及源码分析之后,才知道这是安卓或者说Java封装API的原因。
安卓端,使用Thread实现一个http get请求普遍方法:
<pre name="code" class="java">@Override
public void run(){
HttpURLConnection connection = null;
BufferedInputStream bis = null ;
RandomAccessFile accessFile = null ;
try{
URL url = new URL(url_str);
connection = (HttpURLConnection)url.openConnection();
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
fileSize = connection.getContentLength();
//package name
String con_dis = connection.getHeaderField("Content-Disposition");
fileName = con_dis.substring(con_dis.indexOf('"')+1,con_dis.lastIndexOf('"'));
Log.e("Name", fileName);
//以 路径+文件名 创建文件
File saveFile = new File(path+"/"+fileName);
//操作文件,设置长度
accessFile = new RandomAccessFile(saveFile,"rwd");
accessFile.setLength(fileSize);
//buffer空间
byte[] buffer = new byte[BUFF_SIZE];
bis = new BufferedInputStream(connection.getInputStream(),BUFF_SIZE);
int len ;
//写入buffer空间
while((len = bis.read(buffer,0,BUFF_SIZE))!= -1){
accessFile.write(buffer,0,len); //写入文件
downSize = downSize + len;
downPercent = (downSize*100)/fileSize;
}
/**
* 自动安装
*/
Message msg = new Message();
msg.what = 1 ; //下载完成
Bundle bundle = new Bundle();
bundle.putString("filePath", saveFile.getAbsolutePath());
msg.setData(bundle);
handler.sendMessage(msg);
}catch (Exception e){
e.printStackTrace();
}finally {
//close
if(connection!=null){
connection.disconnect();
}
try{
if(bis!=null){
bis.close();
}
if(accessFile!=null){
accessFile.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
通过Protal admin端日志发现上述代码会call两次URL。先说结论:
1.第一次call发生在url.openConnection();
2.第二次call发生在connection.getInputStream();
openConnection()
如果创建了一个含有正确url的URL对象,并使用该对象的openConnection()方法时,该方法会先尝试进行请求以返回正确的URLConnection对象,请求不成功或协议不匹配则抛出异常。这也解释了为什么在执行完openConnection()之后,可以通过connection.getContentLength()、connection.getHeaderField()等方法获得关于这次请求的响应信息,然后通过这些信息来提前为正式的请求作一些准备(判断响应内容、创建文件、设置文件大小等)。
该方法将返回一个关于这次请求的HttpURLconnection对象,但在我想避免call两接口而想自己创建一个HttpURLConnection对象时,Gradle给我一个这样的回应:
connection = new HttpURLConnection() {
@Override
public void disconnect() {
}
@Override
public boolean usingProxy() {
return false;
}
@Override
public void connect() throws IOException {
}
};
原来HttpURLCoonection是一个抽象的类,那么URL.openConnection()返回的是什么?想要解答疑问,还是要看回源码。
/**
* Returns a new connection to the resource referred to by this URL.
*
* @throws