Android 多线程下载源码实现详细注释

贴出代码供参考:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="下载地址"
    />
<TextView
	android:id="@+id/downloadurl"
	android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
	android:lines="5"
	/>
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="线程数"
    />
<EditText
	android:id="@+id/downloadnum"
	android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
	/>
<ProgressBar
	android:id="@+id/downloadProgressBar"
	android:layout_width="fill_parent" 
	style="?android:attr/progressBarStyleHorizontal"
    android:layout_height="wrap_content" 
	/>
<TextView
	android:id="@+id/downloadinfo"
	android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="下载进度 0"
	/>
<Button
	android:id="@+id/downloadbutton"
	android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="开始下载"
	/>
</LinearLayout>


配置文件设置:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

主函数:
package com.sada.src;

import java.io.File;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;

public class DemoDownloadThreadActivity extends Activity {
 
	private String TAG = "Sada.DemoDownloadThreadActivity";
	private TextView downloadurl;   // 显示下载的地址
	private EditText downloadnum;   // 现在线程数 
	private Button downloadbutton;  // 下载按钮 
	private ProgressBar downloadProgressBar;   // 进度显示器 
	private TextView downloadinfo;      // 信息提示
	private int downloadedSize = 0;     // 当前下载文件的总大小
	private int fileSize = 0;           // 文件的大小
	
	private long downloadtime;   // 耗时
	
	// 网络文件的 下载地址
//	String mtempUrl = "http://219.138.125.22/myweb/mp3/CMP3/JH19.MP3";
	String mtempUrl = "http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3";
    String filename = "";
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
 
		downloadurl = (TextView) findViewById(R.id.downloadurl);
		downloadurl.setText(mtempUrl);
		downloadnum = (EditText) findViewById(R.id.downloadnum);
		downloadinfo = (TextView) findViewById(R.id.downloadinfo);
		downloadbutton = (Button) findViewById(R.id.downloadbutton);
		downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);
		downloadProgressBar.setVisibility(View.VISIBLE);
		downloadProgressBar.setMax(100);
		downloadProgressBar.setProgress(0);
		downloadbutton.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				download();
				downloadtime = SystemClock.currentThreadTimeMillis();
			}
		});
	}
 
	private void download() {
		// 获取SD卡目录
		String dowloadDir = Environment.getExternalStorageDirectory() + "/threaddemodownload/";
		File file = new File(dowloadDir);
		//创建下载目录
		if (!file.exists()) {
			file.mkdirs();
		}
		
		//读取下载线程数,如果为空,则单线程下载
		int downloadTN = Integer.valueOf("".equals(downloadnum.getText().toString()) ? "1" : downloadnum.getText().toString());
		String fileName = "hetang.mp3";
		//开始下载前把下载按钮设置为不可用
		downloadbutton.setClickable(false);
		//进度条设为0
		downloadProgressBar.setProgress(0);
		//启动文件下载线程
		new downloadTask(mtempUrl, Integer.valueOf(downloadTN), dowloadDir + fileName).start();
	}
 
	Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			//当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息
			int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue();
			if (progress == 100) {
				downloadbutton.setClickable(true);
				downloadinfo.setText("下载完成!");
				Dialog mdialog = new AlertDialog.Builder(DemoDownloadThreadActivity.this)
					.setTitle("提示信息")
					.setMessage("下载完成,总用时为:"+(SystemClock.currentThreadTimeMillis()-downloadtime)+"毫秒")
					.setNegativeButton("确定", new DialogInterface.OnClickListener(){
						@Override
						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();
						}
					})
					.create();
				mdialog.show();
			} else {
				downloadinfo.setText("当前进度:" + progress + "%");
			}
			downloadProgressBar.setProgress(progress);
		}
 
	};
 
	/**
	 * 这边文件分块是按照线程数来分的
	 * 还有一个是按照一次最大的文件块来分的这也是实现多线程下载的一个方式
	 * @author WH1107022
	 *
	 */
	public class downloadTask extends Thread {
		private int blockSize, downloadSizeMore;  // 每一个线程应该下载的数据大小,   整除后还剩下的数据大小
		private int threadNum = 5; // 默认是5条
		String urlStr, threadNo, fileName;  // 下载的地址    线程的序号   下载文件的命名
 
		public downloadTask(String urlStr, int threadNum, String fileName) {
			this.urlStr = urlStr;
			this.threadNum = threadNum;
			this.fileName = fileName;
		}
 
		@Override
		public void run() {
			FileDownloadThread[] fds = null;
			try {
				URL url = new URL(urlStr);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				//防止返回-1
				InputStream in = conn.getInputStream();
				//获取下载文件的总大小
				fileSize = conn.getContentLength();
				
				Log.i(TAG, "======================fileSize: " + fileSize);
				//计算每个线程要下载的数据量(一次下载大小)
				blockSize = fileSize / threadNum;
				// 解决整除后百分比计算误差
				downloadSizeMore = (fileSize % threadNum);
				if(downloadSizeMore > 0){ // 有剩余时
					Log.i(TAG, "---------downloadSizeMore = " + downloadSizeMore);
					fds = new FileDownloadThread[threadNum + 1];
				}else {
					Log.i(TAG, "---------downloadSizeMore = " + 0);
					fds = new FileDownloadThread[threadNum];
				}
				
				
				File file = new File(fileName);
				int i = 0;
				for (i = 0; i < threadNum; i ++) {
					Log.i(TAG, "======================i: " + i);
					//启动线程,分别下载自己需要下载的部分
					FileDownloadThread fdt = new FileDownloadThread(url, file, i * blockSize, (i + 1) * blockSize - 1);
					fdt.setName("Thread" + i);
					fdt.start();
					fds[i] = fdt;
				}
				// 剩余部分的下载
				if(downloadSizeMore > 0){
					Log.i(TAG, "======================i: " + i);
					//启动线程,分别下载自己需要下载的部分
					FileDownloadThread fdt = new FileDownloadThread(url, file, i * blockSize, (i * blockSize + downloadSizeMore) - 1);
					fdt.setName("Thread" + i);
					fdt.start();
					fds[i] = fdt;
				}
				boolean finished = false;
				while (!finished) {
					// 先把整除的余数搞定
					downloadedSize = 0;  // downloadSizeMore
					finished = true;
					for (i = 0; i < fds.length; i++) {
						downloadedSize += fds[i].getDownloadSize();
						if (!fds[i].isFinished()) {
							finished = false;
						}
					}
					handler.sendEmptyMessage(0);
					//线程暂停一秒
					sleep(1000);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
 
		}
	}
}

连接类:

package com.sada.src;


import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

import android.util.Log;

public class FileDownloadThread extends Thread {
	private final String TAG = "Sada.FileDownloadThread";
	private static final int BUFFER_SIZE = 1024;
	private URL url;
	private File file;
	private int startPosition;
	private int endPosition;
	private int curPosition;
	// 标识当前线程是否下载完成
	private boolean finished = false;
	private int downloadSize = 0;  // 本线程已经下载的文件的大小

	public FileDownloadThread(URL url, File file, int startPosition,
			int endPosition) {
		this.url = url;
		this.file = file;
		this.startPosition = startPosition;
		this.curPosition = startPosition;
		this.endPosition = endPosition;
	}

	@Override
	public void run() {
		BufferedInputStream bis = null;
		RandomAccessFile fos = null;
		byte[] buf = new byte[BUFFER_SIZE];
		HttpURLConnection conn = null;
		try {
			conn = (HttpURLConnection) url.openConnection();
			conn.setAllowUserInteraction(true);
			// 设置当前线程下载的起止点
			conn.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition);
			Log.i(TAG, Thread.currentThread().getName() + "  bytes=" + startPosition + "-" + endPosition);
			// 使用java中的RandomAccessFile 对文件进行随机读写操作
			fos = new RandomAccessFile(file, "rw");
			// 设置写文件的起始位置
			fos.seek(startPosition);
			bis = new BufferedInputStream(conn.getInputStream());
			// 开始循环以流的形式读写文件
			while (curPosition < endPosition) {
				int len = bis.read(buf, 0, BUFFER_SIZE);
				if (len == -1) {
					break;
				}
				fos.write(buf, 0, len);
				curPosition = curPosition + len;
				if (curPosition > endPosition) {
					downloadSize += len - (curPosition - endPosition) + 1;
				} else {
					downloadSize += len;
				}
			}
			// 下载完成设为true
			this.finished = true;
			bis.close();
			fos.close();
			conn.disconnect();
			conn = null;
			bis = null;
			fos = null;
			buf = null;
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public boolean isFinished() {
		return finished;
	}

	public int getDownloadSize() {
		return downloadSize;
	}
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值