使用HttpURLConnection
实现多线程下载
这个小程序是根据《疯狂Android讲义》(第三版)第13章 Android网络应用,13.3节 使用HTTP访问网络 扩展而来。
使用多线程下载文件可以更快地完成下载任务,因为客户端启动多条线程进行下载就意味着服务器也需要为该客户端提供相应的服务。假设服务器同时最多服务100个用户,在服务器中一个线程对应一个用户,100条线程在计算机内并发执行,也就是由CPU划分时间轮片流执行,如果A应用使用了99条线程下载文件,那么相当于占用了99个用户的资源,自然就拥有了较快的下载速度。不考虑网络因素
实际上并不是客户端并发的下载线程越多下载速度就越快,因为当开启太多并发线程后,应用程序需要维护每条线程的开销,线程同步的开销,这些开销可能反而使下载速度减慢
先看看最终效果
1.这个小程序中负责开启多线程下载的核心类是:DownloadUtil.java
这个类主要做了如下的事情:
- 创建URL对象(本程序使用的是
HttpURLConnection
) - 获取URL指向资源的大小(由
HttpURLConnection.getContentLength()
方法完成) - 在本地磁盘上创建一个与网络资源相同大小的空文件
(RandomAccessFile.setLength()
) - 计算每条线程应该下载网络资源的哪一部分
(从哪个字节开始,到哪个字节结束) - 依次创建,启动多条线程来下载网络资源的指定部分
下面来看具体代码:
- 先来看构造函数
public DownloadUtil(OnDownloadFinish complete) {
this.downloadFinish = complete;
}
OnDownloadFinish
是下载完成后的回调
public interface OnDownloadFinish {
/**
* 所有线程都结束后调用
* @param file 下载好的文件
*/
void onComplete(File file);
}
- 开启下载任务的入口方法
下载前的计算和开启线程下载都在这个方法中完成
/**
* 开始一次下载
* @param sourcePath 目标URL
* @param targetFilePath 目标保存路径
* @param threadNumber 开启的线程数
* @param fileName 保存的文件名
* @throws IOException
*/
public void start(@NonNull String sourcePath, @Nullable String targetFilePath, int threadNumber, @Nullable String fileName) throws IOException {
....
}
- 创建HttpURLConnection对象:
对于一次下载该对象指向的URL资源地址应是同一个,封装成一个方法:
该方法在两个地方被调用到
- 获得URL指向资源大小时。获得大小后关闭该网络连接
- 启动线程下载该线程对应的那部分资源时
private HttpURLConnection getConnection() throws IOException {
URL url = new URL(sourcePath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(1000 * 5);
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept"