HTTPURLConnection继承了URLConnection,因此也可用于向指定网站发送GET请求、POST请求。它在URLConnection的基础上提供了如下便捷的方法:

1、int  getResponseCode():获取服务器的响应代码。

2、String  getResponseMessage():获取服务器的响应消息。

3、String  getRequestMethod():获取发送请求的方法。

4、void  setRequestMethod(String  method):设置发送请求的方法。

下面通过一个实用的示例来示范使用HTTPURLConnection实现多线程下载:

使用多线程下载文件可以更快的完成文件的下载,因为客户端启动多个线程进行下载就意味着服务器也需要为该客户端提供相应的服务。假设服务器同时最多服务100个用户,在服务器中一条线程对应一个用户,100条线程在计算机内并发执行,也就是由CPU划分时间片轮流执行,如果A应用使用了99条线程下载文件,那么相同于占用了99个用户的资源,自然就拥有了较快的下载速度。

注:实际上并不是客户端并发的下载线程越多,程序的下载速度就越快,因为当客户端开启太多的并发线程之后,应用程序需要维护每条线程的开销、线程同步的开销,这些开销反而会导致下载速度降低。

为了实现多线程,程序可按如下步骤进行:

1、创建URL对象。

2、获取指定URL对象所指向资源的大小(由getContentLength()方法实现),此处用到了HTTPURLConnection类。

3、在本地磁盘上创建一个与网络资源相同大小的空文件。

4、计算每条线程应该下载网络资源的哪个部分(从哪个字节开始,到哪个字节结束).

5、依次创建、启动多条线程来下载网络资源的指定部分。

该程序提供的下载工具类:

import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class DownUtil {
  //定义下载资源的路径
  private String path;
  //指定所下载的文件的保存位置
  private String targetFile;
  //定义需要使用多少线程下载资源
  private int threadNum;
  //定义下载的线程对象
  private DownloadThread[] threads;
  //定义下载的文件的总大小
  private int fileSize;
  public DownUtil(String path, String targetFile, int threadNum) {
    super();
    this.path = path;
    this.targetFile = targetFile;
    this.threadNum = threadNum;
    //初始化threads数组
    threads = new DownloadThread[threadNum];
  }
  public void download() throws IOException{
    URL url = new URL(path);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setConnectTimeout(5*1000);
    conn.setRequestMethod("GET");
    conn.setRequestProperty("Accept",
        "image/gif,image/jpeg,image/pjpeg,image/pjpeg,application/x-shockwaveflash" +
        "application/xaml+xml,application/vnd.ms-xpsdocument,application/x-ms-xbap" +
        "application/x-ms-application,application/vnd.ms-excel,application/vnd.ms-powerpoint" +
        "application/msword,*/*");
    conn.setRequestProperty("Accept-Language", "zh-CN");
    conn.setRequestProperty("Charset", "UTF-8");
    conn.addRequestProperty("User-Agent",
        "Mozila/4.0(compatible;MSIE 7.0;Windows NT 5.2;Trident/4.0;" +
        ".NET CLR 1.1.4322;.NET CLR 2.0.5.727;.NET CLR 3.0.04506;.NET CLR " +
        "3.0.4506.2152;.NET CLR 3.5.30729)");
    conn.setRequestProperty("Connection", "Keep-Alive");
    //得到文件大小
    fileSize = conn.getContentLength();
    conn.disconnect();
    int currentPartSize = fileSize/threadNum +1;
    RandomAccessFile file = new RandomAccessFile(targetFile, "rw");
    //设置本地文件的大小
    file.setLength(fileSize);
    file.close();
    for(int i =0 ;i<threadNum ;i++){
      //计算每条线程的下载的开始位置
      int startPos = i * currentPartSize;
      //每个线程使用一个RandomAccessFile进行下载
      RandomAccessFile currentPart = new RandomAccessFile(
            targetFile, "rw");
      //定位该线程的下载位置
      currentPart.seek(startPos);
      //创建下载线程
      threads[i] = new DownloadThread(startPos, currentPartSize, currentPart);
      //启动下载线程
      threads[i].start();
    }
  }
  //获取下载的完成百分比
  public double getCompleteRate(){
    //统计多条线程已经下载的总大小
    int sumSize = 0;
    for(int i =0 ;i<threadNum;i++){
      sumSize += threads[i].length;
    }
    //返回已经完成的百分比
    return sumSize*1.0/fileSize;
  }

  private class DownloadThread extends Thread{
    //当前线程的下载位置
    private int startPos;
    //定义当前线程负责下载的文件大小
    private int currentPartSize;
    //当前线程需要下载的文件块
    private RandomAccessFile currentPart;
    //定义已经该线程已下载的字节数
    public int length;
    public DownloadThread(int startPos, int currentPartSize,
              RandomAccessFile currentPart) {
      super();
      this.startPos = startPos;
      this.currentPartSize = currentPartSize;
      this.currentPart = currentPart;
    }
    @Override
    public void run() {
      try {
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setReadTimeout(5*1000);
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Accept",
            "image/gif,image/jpeg,image/pjpeg,image/pjpeg,application/x-shockwaveflash" +
            "application/xaml+xml,application/vnd.ms-xpsdocument,application/x-ms-xbap" +
            "application/x-ms-application,application/vnd.ms-excel,application/vnd.ms-powerpoint" +
            "application/msword,*/*");
        conn.setRequestProperty("Accept_Language", "zh-CN");
        conn.setRequestProperty("Charset", "UTF-8");
        InputStream inStream = conn.getInputStream();
        //跳过startPos个字节,表明该线程只下载自己负责那部分文件
        inStream.skip(this.startPos);
        byte[] buffer = new byte[1024];
        int hasRead = 0;
        //读取网络数据,并写人本地文件
        while(length < currentPartSize && (hasRead = inStream.read(buffer)) != -1){
                currentPart.write(buffer , 0 , hasRead);
          //累计该线程下载的总大小
          length += hasRead;
        }
      currentPart.close();
      inStream.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
    super.run();
  }

  }
}

上面的DownUtil工具类中包括一个DownloadThread内部类,该内部类run()方法中负责打开远程资源的输入流,并调用InputStream的skip(int)方法跳过指定数量的字节,这样就让该线程读取由它自己负责的部分,提供了上面的DownUtil工具类之后,接下来就可以在Activity中调用该DownUtility类来执行下载任务了。

import java.util.Timer;
import java.util.TimerTask;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SeekBar;

public class MutilThreadDown extends Activity {
  EditText url;
  EditText target;
  Button downBtn;
  SeekBar bar;
  DownUtil downUtil;
  private int mDownStatus;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_mutil_thread_down);
    //获取程序界面中的三个界面控件
    url = (EditText) findViewById(R.id.url);
    target = (EditText) findViewById(R.id.target);
    downBtn = (Button) findViewById(R.id.downBtn);
    bar = (SeekBar) findViewById(R.id.bar);
    //创建一个Handler对象
    final Handler handler = new Handler(){
      @Override
      public void handleMessage(Message msg) {
        if(msg.what == 0x123){
          bar.setProgress(mDownStatus);
        }
      }
    };
    downBtn.setOnClickListener(new OnClickListener() {

      @Override
      public void onClick(View v) {
        // 初始化DownUtil对象
        downUtil = new DownUtil(url.getText().toString(),
        target.getText().toString(), 4);
        try {
          //开始下载
          downUtil.download();
        } catch (Exception e) {
          e.printStackTrace();
        }
        //定义每秒调度获取一次系统的完成进度
        final Timer timer = new Timer();
        timer.schedule(new TimerTask() {

          @Override
          public void run() {
            // 获取下载任务的完成比率
            double completeRate = downUtil.getCompleteRate();
            mDownStatus = (int)(completeRate*100);
            //发送消息通知界面更新进度条
            handler.sendEmptyMessage(0x123);
            //下载完成后取消任务调度
            if(mDownStatus >= 100){
              timer.cancel();
            }
          }
        }, 0, 100);
      }
    });
  }

}

上面的Activity不仅使用了DownUtil来控制程序下载,而且程序还启动了一个定时器,该定时器控制每隔0.1秒查询一次下载进度,并通过程序中的进度条来显示任务的下载进度。

该程序不仅需要访问网络,还需要访问系统SD卡,在SD卡中创建文件,因此必须授予程序访问网络、访问SD卡文件的权限,也就是AndroidManifest.xml文件中增加如下配置:

<!-- 在SD卡中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 向SD卡写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 授权访问网络 -->
<uses-permission android:name="android.permission.INTERNET"/>

注:上面的程序已经实现了多线程下载的核心代码,如果要实现断点下载,则还需要额外增加一个配置文件(所有断点下载工具都会在下载开始生成两个文件:一个是与网络资源相同大小的空文件,一个是配置文件),该配置文件分别记录每个线程已经下载到了那个字节,当网络断开后再次开始下载时,每个线程根据配置文件里记录的位置向后下载即可。

使用HTTP访问网络------使用HTTPURLConnection的更多相关文章

  1. 10_Android中通过HttpUrlConnection访问网络,Handler和多线程使用,读取网络html代码并显示在界面上,ScrollView组件的使用

     编写如下项目: 2 编写Android清单文件 <?xml version="1.0" encoding="utf-8"?> <mani ...

  2. HttpConnection方式访问网络

    参考疯狂android讲义,重点在于学习1.HttpConnection访问网络2.多线程下载文件的处理 主activity: package com.example.multithreaddownl ...

  3. Android 使用 HTTP 协议访问网络

    正在看<第一行代码>,记录一下使用 HTTP 协议访问网络的内容吧! 在Android发送Http请求有两种方式,HttpURLConnection和HttpClient. 1.使用Htt ...

  4. android post 方式 访问网络 实例

    android post 方式 访问网络 实例 因为Android4.0之后对使用网络有特殊要求,已经无法再在主线程中访问网络了,必须使用多线程访问的模式 该实例需要在android配置文件中添加 网 ...

  5. Android使用Http协议访问网络——HttpConnection

    套路篇 使用HttpConnection访问网络一般有如下的套路: 1.获取到HttpConnection的实例,new出一个URL对象,并传入目标的网址,然后调用一下openConnection() ...

  6. 使用HTTP协议访问网络(Android)

    在做项目的过程中需要连接服务器访问数据,还没有接触过Android网络编程方面,参考了<Android第一行代码>,在做的过程中遇到了很多的问题,这里就此记录一下. 先给出访问网络的代码: ...

  7. HttpClient访问网络

    HttpClient项目时Apache提供用于访问网络的类,对访问网络的方法进行了封装.在HttpURlConnection类中的输入输出操作,统一封装成HttpGet.HttpPost.HttpRe ...

  8. iOS HTTP访问网络受限

    HTTP访问网络受限,只需要在项目工程里的Info.plist添加 <key>NSAppTransportSecurity</key> <dict> <key ...

  9. android 使用httpclient访问网络

    在主活动类中,调用一个线程访问网络(android4.0以上耗时的操作不能放在主线程中):       //声明两个Button对象,与一个TextView对象private TextView mTe ...

随机推荐

  1. JAVA中Response的几种用法(设定时间调整到指定页面 ....... )

    <%@ page language="java" import="java.util.*" pageEncoding="gbk"%&g ...

  2. 前端代码新写法——Zen Coding

    是不是还在为html繁琐的标签写法而苦恼? 是不是还在枯燥的写尖括号? Zen Coding的到来将让前端编码不在繁琐.不再拘泥html的尖括号和一堆一堆的标签. 先看看ZenCoding的效果图. ...

  3. Python IDE专用编辑器PyCharm下载及配置安装过程(Ubuntu环境)

    这几天在折腾Python环境,显示把笔记本安装Ubuntu Linux环境系统,然后基本的Python环境都安装完毕之后需要安装传说中在其平台中最好的代码编辑和管理工具PyCharm,于是就根据网上的 ...

  4. tracert 命令详解

    tracert 命令详解 How to Use the TRACERT Utility The TRACERT diagnostic utility determines the route to a ...

  5. hdu 2604 Queuing(dp递推)

    昨晚搞的第二道矩阵快速幂,一开始我还想直接套个矩阵上去(原谅哥模板题做多了),后来看清楚题意后觉得有点像之前做的数位dp的水题,于是就用数位dp的方法去分析,推了好一会总算推出它的递推关系式了(还是菜 ...

  6. Python标准库06 子进程 (subprocess包)

    这里的内容以Linux进程基础和Linux文本流为基础.subprocess包主要功能是执行外部的命令和程序.比如说,我需要使用wget下载文件.我在Python中调用wget程序.从这个意义上来说, ...

  7. JavaScript:引用js文件时的编码格式问题

    JavaScript:引用js文件时的编码格式问题 如果js文件的编码格式是utf-8,并且含有中文,那么按照正常的方法引用,就会出现乱码的情况. 方法/步骤   如果js文件的编码格式是utf-8, ...

  8. C++ 迭代器介绍 [转摘]

    转摘地址为:http://blog.chinaunix.net/uid-20773165-id-1847758.html 迭代器 迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围.迭 ...

  9. 基因组 de novo 组装原理

    Falcon软件的组装流程 为了错误校正,将原始子reads进行overlap 预组装和错误校正 错误校正后reads的overlap检测 overlap的过滤 从overlap构建图 从图构建con ...

  10. java 基础(第一天)

    1.  一个文件里面只能有一个 public 修饰的方法   且方法名与文件名保持一致. 如: public class main(){ } class car(){ } class dog(){ } ...