HTTP网络请求中的GET,POST,PUT,DELETE就对应着查,改,增,删4个操作,而一般用的的是GET和POST。
1.GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连.如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密。
GET方式提交的数据受浏览器及服务器对URL长度的限制。
可以使用GET方式提交数据流,获取数据流或下载文件。

2.POST把提交的数据放置在是HTTP包的包体中,必须要到FORM(表单)。
POST方式提交的数据受服务器对表单处理能力的限制。
可以用POST方式提交数据流或文件,获取数据流。

 

这里介绍的HttpURLConnection,是java的标准类, 在Android2.3版本及以后,HttpURLConnection是最佳的选择。它的API简单,体积较小。默认带gzip压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。
 * 注意:在Android2.2版本之前,HttpURLConnection一直存在着一些令人厌烦的bug,建议用HttpClient。 此外,不建议上传大文件,如果要上传大文件,建议用HttpClient。

 

HttpURLConnection在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重:
对connection对象的一切配置(那一堆set函数)都必须要在connect()之前完成,如果没有connect(),则必须在getInputStream()之前完成。
而getOutputStream().write()上传参数或上传文件必须在getInputStream()之前完成。

也就是说,getInputStream()以后,请求已经发送出去了,所有关于请求的配置都要在此前完成,该函数的返回流已经是服务器的反馈了。

public class HttpURLConnectionUtil {
 public static final int READ_TIMEOUT = 30*1000;
 public static final int CONNECT_TIMEOUT = 10*1000;
 public static final int EXCEPTION_ERR = 888;
 // 文件下载的状态
 public static final int DOWNLOAD_FAIL = -1;  //下载失败
 public static final int DOWNLOAD_PART = 0;  //下载了一部分
 public static final int DOWNLOAD_COMPLETE = 1;  //完全下载
 
 /**
  * 采用POST方式提交数据流
  * POST把提交的数据放置在是HTTP包的包体中,必须要到FORM(表单)。
  * POST方式提交的数据受服务器对表单处理能力的限制。此方法不支持提交大文件
  * @param handler
  *             用消息发送机制返回HTTP Response结果
  * @param urlStr
  *             链接
  * @param params
  *             提交到服务器的参数
  * */
 public static void postWithHttpURLConnection(final Handler handler, final String urlStr,
   final Map<String, String> params){
  StringBuffer data = new StringBuffer();
  Message msg = handler.obtainMessage();
    
  HttpURLConnection conn = null;
  InputStream is = null;
  OutputStream os = null;
  try {
   /* 发送HTTP请求前的Request部分   */
   URL url = new URL(urlStr);
   conn = (HttpURLConnection) url.openConnection();
   conn.setConnectTimeout(CONNECT_TIMEOUT);
   conn.setReadTimeout(READ_TIMEOUT);
   conn.setRequestMethod("POST");
   // 设置是否向connection输出,因为这个是post请求,参数要放在http正文内,因此需要设为true
   conn.setDoOutput(true);
   // 要读取http的反馈,因此需要设为true
   conn.setDoInput(true);
   // 说明正文是urlencoded编码过的form参数,同时我们对参数要进行UTF_8 转码成byte字节流
   conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
   // Post 请求不能使用缓存
   conn.setUseCaches(false);
   conn.setInstanceFollowRedirects(true);   
   // 正文的内容是通过outputStream流写入
   if( params != null ) {
    StringBuffer param = new StringBuffer();
    int index = 0;
    for (Map.Entry<String, String> entry : params.entrySet()) {
     String key = entry.getKey();
     String value = entry.getValue();
     if( index > 0 ){
      param.append("&");
     }
     param.append(key);
     param.append("=");
     param.append(value);
     index += 1;
    }
    if(param.length() > 0) {
     os = conn.getOutputStream();
     // 这种格式数据value先进行UTF_8 转码成byte字节流
     os.write(param.toString().getBytes("UTF_8"));
    }
   }
   /* Request部分配置完成 */
       
   /* 发送HTTP请求后的Response部分 */
   int responseCode = conn.getResponseCode();
   is = conn.getInputStream();
   if ( is != null ) {
    int readSize = 0;
    byte[] buffer = new byte[1024];
    while( ( readSize = is.read(buffer) ) != -1 ) {
     //将流字节通过UTF-8转码成字符串
     String str = new String(buffer,"UTF_8");
     data.append(str);
    }
   }
   String json = data.toString();
   msg.what = responseCode;
   msg.obj = json;
  } catch (Exception e) {
   msg.what = EXCEPTION_ERR;
   msg.obj = e.getMessage();
  } finally {
   // 不管是否发生异常,都会调用的代码段
   msg.sendToTarget();
   if (os!=null){
    try {
     os.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
   }
   if (is!=null){
    try {
     is.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
   if (conn!=null){
    conn.disconnect();
   }
  }
 }
 
 /**
  * 采用GET方式请求数据流
  * GET提交的数据显示放置在HTTP协议头中,以?分割URL和传输数据,参数之间以&相连.
  * GET提交的数据受浏览器及服务器对URL长度的限制,一般是1024字节。
  * @param handler
  *             用消息发送机制返回HTTP Response结果
  * @param urlStr
  *             链接
  * */
 public static void getWithHttpURLConnection(final Handler handler, final String urlStr){
  StringBuffer data = new StringBuffer();
  Message msg = handler.obtainMessage();
  HttpURLConnection conn = null;
  InputStream is = null;
  try {
   URL url = new URL(urlStr);
   conn = (HttpURLConnection) url.openConnection();
   conn.setConnectTimeout(CONNECT_TIMEOUT);
   conn.setReadTimeout(READ_TIMEOUT);
   conn.setRequestMethod("GET");
      
   int responseCode = conn.getResponseCode();
   is = conn.getInputStream();
   if( is != null ) {
    int readSize = 0;
    byte[] buffer = new byte[1024];
    is = conn.getInputStream();
    while( ( readSize = is.read(buffer) ) != -1 ) {
     //将流字节通过UTF-8转码成字符串
     String str = new String(buffer,"UTF_8");
     data.append(str);
    }
   }
   msg.what = responseCode;
   msg.obj = data.toString();
  } catch (Exception e) {
   msg.what = EXCEPTION_ERR;
   msg.obj = e.getMessage();
  } finally {
   msg.sendToTarget();
   if (conn!=null){
    conn.disconnect();
   }
   if (is!=null){
    try {
     is.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }
 }
 
 /**
  * 使用GET的方法下载大文件,可以支持断点续传。下载完的文件保存在用户定义的指定位置。
  * 
  * @param handler
  *             与主线程的交互,返回下载结果状态
  * @param urlStr
  *     下载链接
  * @param filePath
  *     下载文件保存路径
  * @param fileName
  *     下载文件的文件名
  * */
 public static void downloadFileWithHttpURLConnection(final Handler handler, final String urlStr, 
   final String filePath, final String fileName) {
  DownloadFileInfo fileInfo = new DownloadFileInfo(urlStr,filePath,fileName);
  int status = downloadWithHttpURLConnection(fileInfo);
  if( status == DOWNLOAD_PART ) {
   if( shouldRangeDownload(fileInfo) ) {
    status = downloadRangeWithHttpURLConnection(fileInfo);
   }
  }
  Message msg = handler.obtainMessage();
  msg.what = status;
  msg.obj = "";
  handler.sendMessage(msg);
 }
 
 /**
  * 判断是否可以断点续传
  * 
  * @param DownloadFileInfo 保存下载信息:
  *    mURL:下载链接
  *    mFilePath:指定下载文件保存路径
  *    mFileName:下载文件的文件名
  *    mCompleteFileLength:待下载文件的Size
  *    mCurrentFileLength:已经下载的文件的Size,用于断点续传
  *    mEtag:服务器为某个文件生产的唯一标识值,每次文件有更新该值就会变化。
  * */
 private static boolean shouldRangeDownload(DownloadFileInfo fileInfo){
  File file = new File(fileInfo.mFilePath+File.separator+fileInfo.mFileName);
  if(!file.exists()){
   // 原来下载的文件已经被删除了,重新下载
   fileInfo.clearFileSizeRecord();
   return false;
  }
  
  HttpURLConnection conn = null;
  try {
   URL url = new URL(fileInfo.mURL);
   conn = (HttpURLConnection) url.openConnection();
   conn.setConnectTimeout(CONNECT_TIMEOUT);
   conn.setRequestMethod("GET");
   
   String acceptRange= conn.getHeaderField("Accept-Ranges");
   String etag = conn.getHeaderField("ETag");
   if( acceptRange!=null && acceptRange.equalsIgnoreCase("bytes") &&
     fileInfo.mEtag!=null && etag!=null && etag.equalsIgnoreCase( fileInfo.mEtag )) {
    return true;
   } else {
    // 1. 服务器不支持断点续传
    // 2. ETag改变了
    // 应该重新下载整个文件
    return false;
   }
   
  } catch (Exception e) {
   return false;
  } finally {
   if (conn!=null){
    conn.disconnect();
   }
  }
 }
 /**
  * 一次性全部下载
  * 1. 不要设置ReadTimeOut,如果要设置,最好时间长一些,因为大文件的下载本来就耗时
  * 2. 下载过程采用一边读输入流,一边写入文件的方法,节约内存
  * 3. 如果只下载了一部分就被中断,但是服务器不支持断点续传的话,必须重新下载
  */
 public static int downloadWithHttpURLConnection(DownloadFileInfo fileInfo) {
  HttpURLConnection conn = null;
  InputStream is = null;
  RandomAccessFile savedfile = null;
  try {
   URL url = new URL(fileInfo.mURL);
   conn = (HttpURLConnection) url.openConnection();
   conn.setConnectTimeout(CONNECT_TIMEOUT);
   conn.setRequestMethod("GET");
   //保存文件的标示
   String etag = conn.getHeaderField("ETag");
   if(etag!=null){
    fileInfo.mEtag = etag;
   }
   
   //新建需要写入的RandomAccessFile
   File dir = new File(fileInfo.mFilePath);
   if(!dir.exists()){
    dir.mkdirs();
   }
   File file = new File(fileInfo.mFilePath+File.separator+fileInfo.mFileName);
   if(!file.exists()){
    file.createNewFile();
   }
   savedfile = new RandomAccessFile(file,"rwd");
   
   int responseCode = conn.getResponseCode();
   if ( responseCode == 200 ) {//用来表示请求成功.
    int len = conn.getContentLength();
    if( len <= 0 ) {
     return DOWNLOAD_FAIL;
    }
    fileInfo.mCompleteFileLength = len;
    
    int readSize = 0;
    byte[] buffer = new byte[1024];//1k内存
    is = conn.getInputStream();
    while( ( readSize = is.read(buffer) ) != -1 ) {
     // 循环从输入流中读1k数据,写入文件
     savedfile.write(buffer, 0, readSize);
     fileInfo.mCurrentFileLength += readSize;
    }
   } else {
    return DOWNLOAD_FAIL;
   }
   int status = DOWNLOAD_FAIL;
   if( fileInfo.mCurrentFileLength > 0 ) {
    if( fileInfo.mCurrentFileLength == fileInfo.mCompleteFileLength ) {
     status = DOWNLOAD_COMPLETE;
    } else {
     status = DOWNLOAD_PART;
    }
   }
   return status;
  } catch (Exception e) {
   int status = DOWNLOAD_FAIL;
   if( fileInfo.mCurrentFileLength > 0 ) {
    status = DOWNLOAD_PART;
   }
   return status;
  } finally {
   if( conn != null ) {
    conn.disconnect();
   }
   if( is != null ) {
    try {
     is.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
   if( savedfile != null ) {
    try {
     savedfile.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }
 }
 
 /** 
  * 断点续传下载
  * 注意:断点续传成功的getResponseCode()是206,不是200
  */
 public static int downloadRangeWithHttpURLConnection(DownloadFileInfo fileInfo) {
  HttpURLConnection conn = null;
  InputStream is = null;
  RandomAccessFile savedfile = null;
  try {
   URL url = new URL(fileInfo.mURL);
   conn = (HttpURLConnection) url.openConnection();
   conn.setConnectTimeout(CONNECT_TIMEOUT);
   conn.setRequestMethod("GET");
   
   int startPos = fileInfo.mCurrentFileLength;//开始位置
   conn.setRequestProperty("Range", "bytes=" + startPos + "-");//设置获取实体数据的范围
            conn.connect();
            
   //新建需要写入的RandomAccessFile
   File file = new File(fileInfo.mFilePath+File.separator+fileInfo.mFileName);
   savedfile = new RandomAccessFile(file,"rwd");
   savedfile.seek(startPos);
    
   int responseCode = conn.getResponseCode();
   if ( responseCode == 206 ) {//断点续传成功的反馈值是206,不是200
    int len = conn.getContentLength();
    if( len <= 0 ) {
     return DOWNLOAD_FAIL;
    }
    
    byte[] buffer = new byte[1024];
    int readSize = 0;
    is = conn.getInputStream();
    while( (readSize=is.read(buffer)) != -1 ) {
     savedfile.write(buffer, 0, readSize);
     fileInfo.mCurrentFileLength += readSize;
    }
   } else {
    return DOWNLOAD_FAIL;
   }
   int status = DOWNLOAD_FAIL;
   if( fileInfo.mCurrentFileLength > 0 ) {
    if( fileInfo.mCurrentFileLength == fileInfo.mCompleteFileLength ) {
     status = DOWNLOAD_COMPLETE;
    } else {
     status = DOWNLOAD_PART;
    }
   }
   return status;
  } catch (Exception e) {
   int status = DOWNLOAD_FAIL;
   if( fileInfo.mCurrentFileLength > 0 ) {
    status = DOWNLOAD_PART;
   }
   return status;
  } finally {
   if (conn!=null){
    conn.disconnect();
   }
   if(is!=null){
    try {
     is.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
   if(savedfile!=null){
    try {
     savedfile.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }
 }
}
public class HttpURLConnectionUtil {
 public static final int READ_TIMEOUT = 30*1000;
 public static final int CONNECT_TIMEOUT = 10*1000;
 public static final int EXCEPTION_ERR = 888;
 // 文件下载的状态
 public static final int DOWNLOAD_FAIL = -1;  //下载失败
 public static final int DOWNLOAD_PART = 0;  //下载了一部分
 public static final int DOWNLOAD_COMPLETE = 1;  //完全下载
 
 /**
  * 采用POST方式提交数据流
  * POST把提交的数据放置在是HTTP包的包体中,必须要到FORM(表单)。
  * POST方式提交的数据受服务器对表单处理能力的限制。此方法不支持提交大文件
  * @param handler
  *             用消息发送机制返回HTTP Response结果
  * @param urlStr
  *             链接
  * @param params
  *             提交到服务器的参数
  * */
 public static void postWithHttpURLConnection(final Handler handler, final String urlStr,
   final Map<String, String> params){
  StringBuffer data = new StringBuffer();
  Message msg = handler.obtainMessage();
    
  HttpURLConnection conn = null;
  InputStream is = null;
  OutputStream os = null;
  try {
   /* 发送HTTP请求前的Request部分   */
   URL url = new URL(urlStr);
   conn = (HttpURLConnection) url.openConnection();
   conn.setConnectTimeout(CONNECT_TIMEOUT);
   conn.setReadTimeout(READ_TIMEOUT);
   conn.setRequestMethod("POST");
   // 设置是否向connection输出,因为这个是post请求,参数要放在http正文内,因此需要设为true
   conn.setDoOutput(true);
   // 要读取http的反馈,因此需要设为true
   conn.setDoInput(true);
   // 说明正文是urlencoded编码过的form参数,同时我们对参数要进行UTF_8 转码成byte字节流
   conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
   // Post 请求不能使用缓存
   conn.setUseCaches(false);
   conn.setInstanceFollowRedirects(true);   
   // 正文的内容是通过outputStream流写入
   if( params != null ) {
    StringBuffer param = new StringBuffer();
    int index = 0;
    for (Map.Entry<String, String> entry : params.entrySet()) {
     String key = entry.getKey();
     String value = entry.getValue();
     if( index > 0 ){
      param.append("&");
     }
     param.append(key);
     param.append("=");
     param.append(value);
     index += 1;
    }
    if(param.length() > 0) {
     os = conn.getOutputStream();
     // 这种格式数据value先进行UTF_8 转码成byte字节流
     os.write(param.toString().getBytes("UTF_8"));
    }
   }
   /* Request部分配置完成 */
       
   /* 发送HTTP请求后的Response部分 */
   int responseCode = conn.getResponseCode();
   is = conn.getInputStream();
   if ( is != null ) {
    int readSize = 0;
    byte[] buffer = new byte[1024];
    while( ( readSize = is.read(buffer) ) != -1 ) {
     //将流字节通过UTF-8转码成字符串
     String str = new String(buffer,"UTF_8");
     data.append(str);
    }
   }
   String json = data.toString();
   msg.what = responseCode;
   msg.obj = json;
  } catch (Exception e) {
   msg.what = EXCEPTION_ERR;
   msg.obj = e.getMessage();
  } finally {
   // 不管是否发生异常,都会调用的代码段
   msg.sendToTarget();
   if (os!=null){
    try {
     os.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
   }
   if (is!=null){
    try {
     is.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
   if (conn!=null){
    conn.disconnect();
   }
  }
 }
 
 /**
  * 采用GET方式请求数据流
  * GET提交的数据显示放置在HTTP协议头中,以?分割URL和传输数据,参数之间以&相连.
  * GET提交的数据受浏览器及服务器对URL长度的限制,一般是1024字节。
  * @param handler
  *             用消息发送机制返回HTTP Response结果
  * @param urlStr
  *             链接
  * */
 public static void getWithHttpURLConnection(final Handler handler, final String urlStr){
  StringBuffer data = new StringBuffer();
  Message msg = handler.obtainMessage();
  HttpURLConnection conn = null;
  InputStream is = null;
  try {
   URL url = new URL(urlStr);
   conn = (HttpURLConnection) url.openConnection();
   conn.setConnectTimeout(CONNECT_TIMEOUT);
   conn.setReadTimeout(READ_TIMEOUT);
   conn.setRequestMethod("GET");
      
   int responseCode = conn.getResponseCode();
   is = conn.getInputStream();
   if( is != null ) {
    int readSize = 0;
    byte[] buffer = new byte[1024];
    is = conn.getInputStream();
    while( ( readSize = is.read(buffer) ) != -1 ) {
     //将流字节通过UTF-8转码成字符串
     String str = new String(buffer,"UTF_8");
     data.append(str);
    }
   }
   msg.what = responseCode;
   msg.obj = data.toString();
  } catch (Exception e) {
   msg.what = EXCEPTION_ERR;
   msg.obj = e.getMessage();
  } finally {
   msg.sendToTarget();
   if (conn!=null){
    conn.disconnect();
   }
   if (is!=null){
    try {
     is.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }
 }
 
 /**
  * 使用GET的方法下载大文件,可以支持断点续传。下载完的文件保存在用户定义的指定位置。
  * 
  * @param handler
  *             与主线程的交互,返回下载结果状态
  * @param urlStr
  *     下载链接
  * @param filePath
  *     下载文件保存路径
  * @param fileName
  *     下载文件的文件名
  * */
 public static void downloadFileWithHttpURLConnection(final Handler handler, final String urlStr, 
   final String filePath, final String fileName) {
  DownloadFileInfo fileInfo = new DownloadFileInfo(urlStr,filePath,fileName);
  int status = downloadWithHttpURLConnection(fileInfo);
  if( status == DOWNLOAD_PART ) {
   if( shouldRangeDownload(fileInfo) ) {
    status = downloadRangeWithHttpURLConnection(fileInfo);
   }
  }
  Message msg = handler.obtainMessage();
  msg.what = status;
  msg.obj = "";
  handler.sendMessage(msg);
 }
 
 /**
  * 判断是否可以断点续传
  * 
  * @param DownloadFileInfo 保存下载信息:
  *    mURL:下载链接
  *    mFilePath:指定下载文件保存路径
  *    mFileName:下载文件的文件名
  *    mCompleteFileLength:待下载文件的Size
  *    mCurrentFileLength:已经下载的文件的Size,用于断点续传
  *    mEtag:服务器为某个文件生产的唯一标识值,每次文件有更新该值就会变化。
  * */
 private static boolean shouldRangeDownload(DownloadFileInfo fileInfo){
  File file = new File(fileInfo.mFilePath+File.separator+fileInfo.mFileName);
  if(!file.exists()){
   // 原来下载的文件已经被删除了,重新下载
   fileInfo.clearFileSizeRecord();
   return false;
  }
  
  HttpURLConnection conn = null;
  try {
   URL url = new URL(fileInfo.mURL);
   conn = (HttpURLConnection) url.openConnection();
   conn.setConnectTimeout(CONNECT_TIMEOUT);
   conn.setRequestMethod("GET");
   
   String acceptRange= conn.getHeaderField("Accept-Ranges");
   String etag = conn.getHeaderField("ETag");
   if( acceptRange!=null && acceptRange.equalsIgnoreCase("bytes") &&
     fileInfo.mEtag!=null && etag!=null && etag.equalsIgnoreCase( fileInfo.mEtag )) {
    return true;
   } else {
    // 1. 服务器不支持断点续传
    // 2. ETag改变了
    // 应该重新下载整个文件
    return false;
   }
   
  } catch (Exception e) {
   return false;
  } finally {
   if (conn!=null){
    conn.disconnect();
   }
  }
 }
 /**
  * 一次性全部下载
  * 1. 不要设置ReadTimeOut,如果要设置,最好时间长一些,因为大文件的下载本来就耗时
  * 2. 下载过程采用一边读输入流,一边写入文件的方法,节约内存
  * 3. 如果只下载了一部分就被中断,但是服务器不支持断点续传的话,必须重新下载
  */
 public static int downloadWithHttpURLConnection(DownloadFileInfo fileInfo) {
  HttpURLConnection conn = null;
  InputStream is = null;
  RandomAccessFile savedfile = null;
  try {
   URL url = new URL(fileInfo.mURL);
   conn = (HttpURLConnection) url.openConnection();
   conn.setConnectTimeout(CONNECT_TIMEOUT);
   conn.setRequestMethod("GET");
   //保存文件的标示
   String etag = conn.getHeaderField("ETag");
   if(etag!=null){
    fileInfo.mEtag = etag;
   }
   
   //新建需要写入的RandomAccessFile
   File dir = new File(fileInfo.mFilePath);
   if(!dir.exists()){
    dir.mkdirs();
   }
   File file = new File(fileInfo.mFilePath+File.separator+fileInfo.mFileName);
   if(!file.exists()){
    file.createNewFile();
   }
   savedfile = new RandomAccessFile(file,"rwd");
   
   int responseCode = conn.getResponseCode();
   if ( responseCode == 200 ) {//用来表示请求成功.
    int len = conn.getContentLength();
    if( len <= 0 ) {
     return DOWNLOAD_FAIL;
    }
    fileInfo.mCompleteFileLength = len;
    
    int readSize = 0;
    byte[] buffer = new byte[1024];//1k内存
    is = conn.getInputStream();
    while( ( readSize = is.read(buffer) ) != -1 ) {
     // 循环从输入流中读1k数据,写入文件
     savedfile.write(buffer, 0, readSize);
     fileInfo.mCurrentFileLength += readSize;
    }
   } else {
    return DOWNLOAD_FAIL;
   }
   int status = DOWNLOAD_FAIL;
   if( fileInfo.mCurrentFileLength > 0 ) {
    if( fileInfo.mCurrentFileLength == fileInfo.mCompleteFileLength ) {
     status = DOWNLOAD_COMPLETE;
    } else {
     status = DOWNLOAD_PART;
    }
   }
   return status;
  } catch (Exception e) {
   int status = DOWNLOAD_FAIL;
   if( fileInfo.mCurrentFileLength > 0 ) {
    status = DOWNLOAD_PART;
   }
   return status;
  } finally {
   if( conn != null ) {
    conn.disconnect();
   }
   if( is != null ) {
    try {
     is.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
   if( savedfile != null ) {
    try {
     savedfile.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }
 }
 
 /** 
  * 断点续传下载
  * 注意:断点续传成功的getResponseCode()是206,不是200
  */
 public static int downloadRangeWithHttpURLConnection(DownloadFileInfo fileInfo) {
  HttpURLConnection conn = null;
  InputStream is = null;
  RandomAccessFile savedfile = null;
  try {
   URL url = new URL(fileInfo.mURL);
   conn = (HttpURLConnection) url.openConnection();
   conn.setConnectTimeout(CONNECT_TIMEOUT);
   conn.setRequestMethod("GET");
   
   int startPos = fileInfo.mCurrentFileLength;//开始位置
   conn.setRequestProperty("Range", "bytes=" + startPos + "-");//设置获取实体数据的范围
            conn.connect();
            
   //新建需要写入的RandomAccessFile
   File file = new File(fileInfo.mFilePath+File.separator+fileInfo.mFileName);
   savedfile = new RandomAccessFile(file,"rwd");
   savedfile.seek(startPos);
    
   int responseCode = conn.getResponseCode();
   if ( responseCode == 206 ) {//断点续传成功的反馈值是206,不是200
    int len = conn.getContentLength();
    if( len <= 0 ) {
     return DOWNLOAD_FAIL;
    }
    
    byte[] buffer = new byte[1024];
    int readSize = 0;
    is = conn.getInputStream();
    while( (readSize=is.read(buffer)) != -1 ) {
     savedfile.write(buffer, 0, readSize);
     fileInfo.mCurrentFileLength += readSize;
    }
   } else {
    return DOWNLOAD_FAIL;
   }
   int status = DOWNLOAD_FAIL;
   if( fileInfo.mCurrentFileLength > 0 ) {
    if( fileInfo.mCurrentFileLength == fileInfo.mCompleteFileLength ) {
     status = DOWNLOAD_COMPLETE;
    } else {
     status = DOWNLOAD_PART;
    }
   }
   return status;
  } catch (Exception e) {
   int status = DOWNLOAD_FAIL;
   if( fileInfo.mCurrentFileLength > 0 ) {
    status = DOWNLOAD_PART;
   }
   return status;
  } finally {
   if (conn!=null){
    conn.disconnect();
   }
   if(is!=null){
    try {
     is.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
   if(savedfile!=null){
    try {
     savedfile.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }
 }
}