1.下载类
package com.young.download.factory;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
import android.util.Log;
/**
*
* 文件下载类
*
*/
public class FileDownloadThread extends Thread {
private static final String TAG = "FileDownloadThread";
/** 缓冲区 */
private static final int BUFF_SIZE = 1024;
/** 需要下载的URL */
private URL url;
/** 缓存的FIle */
private File file;
/** 开始位置 */
private int startPosition;
/** 结束位置 */
private int endPosition;
/** 当前位置 */
private int curPosition;
/** 完成 */
private boolean finished = false;
/** 已经下载多少 */
private int downloadSize = 0;
/***
* 分块文件下载,可以创建多线程模式
*
* @param url
* 下载的URL
* @param file
* 下载的文件
* @param startPosition
* 开始位置
* @param endPosition
* 结束位置
*/
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;
Log.e(TAG, toString());
}
@Override
public void run() {
BufferedInputStream bis = null;
RandomAccessFile rAccessFile = null;
byte[] buf = new byte[BUFF_SIZE];
URLConnection conn = null;
try {
conn = url.openConnection();
conn.setConnectTimeout(10000);// 设置超时
conn.setReadTimeout(10000);
conn.setAllowUserInteraction(true);
System.out.println(this.getName() + " startPosition "
+ startPosition + " endPosition " + endPosition);
// 根据范围下载数据
conn.setRequestProperty("Range", "bytes=" + (startPosition) + "-"
+ endPosition);
// 读写
rAccessFile = new RandomAccessFile(file, "rwd");
// 从某个地方开始写入数据
rAccessFile.seek(startPosition);
bis = new BufferedInputStream(conn.getInputStream(), BUFF_SIZE);
// 当前位置小于结束位置 继续下载
while (curPosition < endPosition)
{
int len = bis.read(buf, 0, BUFF_SIZE);
// 下载完成
if (len == -1) {
break;
}
rAccessFile.write(buf, 0, len);
curPosition = curPosition + len;
// 如果下载多了,则减去多余部分
if (curPosition > endPosition) {
System.out.println(" curPosition > endPosition !!!!");
int extraLen = curPosition - endPosition;
downloadSize += (len - extraLen + 1);
} else {
downloadSize += len;
}
}
this.finished = true; // 当前阶段下载完成
Log.e(TAG, "当前" + this.getName() + "下载完成");
} catch (Exception e) {
Log.e(TAG, "download error Exception " + e.getMessage());
e.printStackTrace();
} finally {
try {
// 关闭流
bis.close();
rAccessFile.close();
} catch (IOException e) {
Log.e("AccessFile", "AccessFile IOException " + e.getMessage());
}
}
super.run();
}
/**
* 是否完成当前段下载完成
*
* @return
*/
public boolean isFinished() {
return finished;
}
/**
* 已经下载多少
*
* @return
*/
public int getDownloadSize() {
return downloadSize;
}
@Override
public String toString() {
return "FileDownloadThread [url=" + url + ", file=" + file
+ ", startPosition=" + startPosition + ", endPosition="
+ endPosition + ", curPosition=" + curPosition + ", finished="
+ finished + ", downloadSize=" + downloadSize + "]";
}
}
2.更新信息处理类
package com.young.download.factory;
import java.io.File;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.young.download.util.FileUtil;
/**
* 多线程下载,UI更新类
*
**/
public class MultiThreadDownload extends Thread {
private static final String TAG = "MultiThreadDownload";
/** 每一个线程需要下载的大小 */
private int blockSize;
/***
* 线程数量<br>
* 默认为5个线程下载
*/
private int threadNum = 2;
/*** 文件大小 */
private int fileSize;
/** * 已经下载多少 */
private int downloadSize;
/** 文件的url,线程编号,文件名称 */
private String UrlStr, ThreadNo, fileName;
/*** 保存的路径 */
private String savePath;
/** 下载的百分比 */
private int downloadPercent = 0;
/** 下载的 平均速度 */
private int downloadSpeed = 0;
/** 下载用的时间 */
private int usedTime = 0;
/** 当前时间 */
private long curTime;
/** 是否已经下载完成 */
private boolean completed = false;
private Handler handler;
/**
* 下载的构造函数
*
* @param url
* 请求下载的URL
* @param handler
* UI更新使用
* @param savePath
* 保存文件的路径
*/
public MultiThreadDownload(Handler handler, String url, String savePath) {
this.handler = handler;
this.UrlStr = url;
this.savePath = savePath;
Log.e(TAG, toString());
}
@Override
public void run() {
FileDownloadThread[] fds = new FileDownloadThread[threadNum];// 设置线程数量
try {
URL url = new URL(UrlStr);
URLConnection conn = url.openConnection();
fileSize = conn.getContentLength();
this.fileName = FileUtil.getFileName(UrlStr);
// 只创建一个文件,saveFile下载内容
File saveFile = new File(savePath + "/" + fileName);
Log.e(TAG, "文件一共:" + fileSize + " savePath " + savePath
+ " fileName " + fileName);
// 下载的文件内容
RandomAccessFile accessFile = new RandomAccessFile(saveFile, "rwd");
// 设置本地文件的长度和下载文件相同
accessFile.setLength(fileSize);
accessFile.close();
// Handler更新UI,发送消息
sendMsg(FileUtil.startDownloadMeg);
// 每个线程下载的数据量
blockSize = ((fileSize % threadNum) == 0) ? (fileSize / threadNum)
: (fileSize / threadNum + 1);
Log.e(TAG, "每个线程分别下载 :" + blockSize);
for (int i = 0; i < threadNum; i++) {
int curThreadEndPosition = (i + 1) != threadNum ? ((i + 1)
* blockSize - 1) : fileSize;
FileDownloadThread fdt = new FileDownloadThread(url, saveFile,
i * blockSize, curThreadEndPosition);
fdt.setName("thread" + i);
fdt.start();
fds[i] = fdt;
}
/**
* 获取数据,更新UI,直到所有下载线程都下载完成。
*/
boolean finished = false;
// 开始时间,放在循环外,求解的usedTime就是总时间
long startTime = System.currentTimeMillis();
while (!finished) {
downloadSize = 0;
finished = true;
for (int i = 0; i < fds.length; i++) {
downloadSize += fds[i].getDownloadSize();
if (!fds[i].isFinished()) {
finished = false;
}
}
downloadPercent = (downloadSize * 100) / fileSize;
curTime = System.currentTimeMillis();
System.out.println("curTime = " + curTime + " downloadSize = "
+ downloadSize + " usedTime "
+ (int) ((curTime - startTime) / 1000));
usedTime = (int) ((curTime - startTime) / 1000);
if (usedTime == 0)
usedTime = 1;
downloadSpeed = (downloadSize / usedTime) / 1024;
sleep(1000);/* 1秒钟刷新一次界面 */
sendMsg(FileUtil.updateDownloadMeg);
}
Log.e(TAG, "下载完成");
completed = true;
sendMsg(FileUtil.endDownloadMeg);
} catch (Exception e) {
Log.e(TAG, "multi file error Exception " + e.getMessage());
e.printStackTrace();
}
super.run();
}
/**
* 得到文件的大小
*
* @return
*/
public int getFileSize() {
return this.fileSize;
}
/**
* 得到已经下载的数量
*
* @return
*/
public int getDownloadSize() {
return this.downloadSize;
}
/**
* 获取下载百分比
*
* @return
*/
public int getDownloadPercent() {
return this.downloadPercent;
}
/**
* 获取下载速度
*
* @return
*/
public int getDownloadSpeed() {
return this.downloadSpeed;
}
/**
* 修改默认线程数
*
* @param threadNum
*/
public void setThreadNum(int threadNum) {
this.threadNum = threadNum;
}
/**
* 分块下载完成的标志
*
* @return
*/
public boolean isCompleted() {
return this.completed;
}
@Override
public String toString() {
return "MultiThreadDownload [threadNum=" + threadNum + ", fileSize="
+ fileSize + ", UrlStr=" + UrlStr + ", ThreadNo=" + ThreadNo
+ ", savePath=" + savePath + "]";
}
/**
* 发送消息,用户提示
* */
private void sendMsg(int what) {
Message msg = new Message();
msg.what = what;
handler.sendMessage(msg);
}
}
3.Activity类
package com.young.download;
import java.io.File;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.young.download.factory.MultiThreadDownload;
import com.young.download.util.FileUtil;
public class MainActivity extends Activity implements OnClickListener {
protected static final String TAG = "MainActivity";
private Button button;
private ProgressBar pb;
// 需要下载的文件
private String url = "http://gdown.baidu.com/data/wisegame/3c00add7144d3915/kugouyinle.apk";
private MultiThreadDownload mUpdateUIThread = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
button = (Button) this.findViewById(R.id.button);
button.setOnClickListener(this);
pb = (ProgressBar) this.findViewById(R.id.pb);
mUpdateUIThread = new MultiThreadDownload(handler, url,
FileUtil.setMkdir(this) + File.separator);
}
@Override
public void onClick(View v) {
mUpdateUIThread.start();
}
// 对返回的数据进行处理
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case FileUtil.startDownloadMeg:
// 设置进度条中最大的值是文件的大小
pb.setMax(mUpdateUIThread.getFileSize());
break;
case FileUtil.updateDownloadMeg:
if (!mUpdateUIThread.isCompleted()) // 下载
{
Log.e(TAG, "已下载:" + mUpdateUIThread.getDownloadSize());
pb.setProgress(mUpdateUIThread.getDownloadSize());
button.setText("下载速度:" + mUpdateUIThread.getDownloadSpeed()
+ "k/秒 下载百分比"
+ mUpdateUIThread.getDownloadPercent() + "%");
} else {
button.setText("下载完成");
}
break;
case FileUtil.endDownloadMeg:
Toast.makeText(MainActivity.this, "下载完成,马上安装",
Toast.LENGTH_SHORT).show();
// 对下载的APK文件进行安装
String filename = FileUtil.getFileName(url);
String str = "/myfile/" + filename;
// 文件的全路径
String fileName = Environment.getExternalStorageDirectory()
+ str;
Intent intent = new Intent(Intent.ACTION_VIEW);
// 设置intent的data和Type属性。
intent.setDataAndType(Uri.fromFile(new File(fileName)),
"application/vnd.android.package-archive");
// 跳转到安装页面
startActivity(intent);
break;
}
super.handleMessage(msg);
}
};
}