今天学习了一些http多线程下载,简单整理一下,便于今后查阅。
URLConnection 可以很方便的与指定的站点交换信息,URLConnect有个子类:HttpURLConnection,HttpURLConnection增加了一些操作http资源的便捷方法。
实现多线程下载步骤如下:
1)创建URL对象。
2)获取指定URL对象所指定资源的大小,使用getContentlength方法。
3)计算每个线程要下载资源的哪个部分(从某个字节开始到哪个字节介绍)。
4)依次创建线程,启动多线程来下载网络指定的部分。
创建downloadUitl类,来创建HttpURLConnetion对象,获取下载资源的大小,创建多线程,来下载指定部分的内容,代码如下:
package com.example.mutidownload; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import android.app.DownloadManager; public class DownloadUntil { //set path of resource String path; //记录资源路径 private int threadNum; //保存下载文件的大小 private long fileSize; //保存下载文件的大小 private String targeFile; //下载文件的本地位置 DownloadThread[] threads; //线程池 public DownloadUntil(String targeFile, int threadNum,String path) { // TODO Auto-generated constructor stub this.path = path; this.threadNum = threadNum; this.targeFile = targeFile; threads = new DownloadThread[threadNum]; } //多线程下载的核心代码 public void download() throws IOException{ URL url = new URL(path); //build http header HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(10000); conn.setRequestMethod("GET"); conn.setRequestProperty("Accept", "image/gif,image/jpeg,*/*"); conn.setRequestProperty("Accept-Language", "zh-CN"); conn.setRequestProperty("Charset", "UTF-8"); conn.setRequestProperty("User-Agent", "Mozilla/4.0(compatible;MSIE6.0;Windows NT 5.0)"); conn.setRequestProperty("Connect", "Keep-Alive"); fileSize = conn.getContentLength(); //获取下载下载文件大小 conn.disconnect(); long currentPartSize = fileSize/threadNum; //计算每个线程要下载的文件大小 RandomAccessFile file = new RandomAccessFile(targeFile, "rw");//打开本地文件,来保存下载数据 file.setLength(fileSize); file.close(); //创建多线程 for(int i = 0; i< threadNum; i++){ long startPos = i*currentPartSize; //计算每个线程所要下载资源的起始位置 RandomAccessFile currentPart = new RandomAccessFile(targeFile, "rw"); currentPart.seek(startPos);//set download focus in local file threads[i] = new DownloadThread(startPos,currentPartSize,currentPart);//create thread threads[i].start(); } } //download rate public float getDownloadProgress(){ int sumSize = 0; for (int i = 0; i < threads.length; i++) { sumSize += threads[i].length; } return (float) (sumSize * 1.0/fileSize * 1.0); } //create download thread private class DownloadThread extends Thread{ public int length = 0; //记录此线程已下载资源的长度 private long startPos; //在下载流中,此线程要下载的初始位置 private long currentPartSize; //此线程下载内容的总长度 private RandomAccessFile currentPart;//本地文件句柄 public DownloadThread(long startPos, long currentPartSize, RandomAccessFile currentPart) { // TODO Auto-generated constructor stub this.startPos = startPos; this.currentPart = currentPart; this.currentPartSize = currentPartSize; } // 单个下载和数据读写的核心代码 public void run(){ try { //creat url connect URL url = new URL(path); HttpURLConnection httpConn = (HttpURLConnection)url.openConnection(); //set header httpConn.setConnectTimeout(10000); httpConn.setRequestMethod("GET"); httpConn.setRequestProperty("Accept", "image/gif,image/jpeg,*/*"); httpConn.setRequestProperty("Accept-Language", "zh-CN"); httpConn.setRequestProperty("Charset", "UTF-8"); httpConn.setRequestProperty("User-Agent", "Mozilla/4.0(compatible;MSIE6.0;Windows NT 5.0)"); httpConn.setRequestProperty("Connect", "Keep-Alive"); InputStream is = httpConn.getInputStream();//get inputstream is.skip(startPos); //把流中的索引指定到此线程所要下载的位置 byte[] buffer = new byte[1024]; int hasRead = 0; while (length < currentPartSize && (hasRead = is.read(buffer)) != -1) { currentPart.write(buffer, 0, hasRead); //把流中数据写入到本地文件中(在前面已经指定了文件索引,所以在此直接保存就可以 length+=hasRead; } currentPart.close(); is.close(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
Activity 部分代码:
package com.example.mutidownload; import java.io.IOException; 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.ProgressBar; public class MainActivity extends Activity { int mProgress = 0; ProgressBar progress; Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); if (msg.what == 0x01) { progress.setProgress(mProgress); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final EditText url = (EditText)findViewById(R.id.url); progress = (ProgressBar)findViewById(R.id.progress); Button download = (Button)findViewById(R.id.download); download.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub final DownloadUntil donwloadUntil = new DownloadUntil(url.getText().toString(), 5, "mnt/sd/download"); try { donwloadUntil.download(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } final Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { // TODO Auto-generated method stub mProgress = (int)donwloadUntil.getDownloadProgress()* 100; handler.sendEmptyMessage(0x01); if (mProgress > 100) { timer.cancel(); } } }, 0, 100); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }