添加监听
package com.ldw.multiDownload;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
public class DownloadFile{
private static final String DOWNLOAD_INIT = "1";
private static final String DOWNLOAD_ING = "2";
private static final String DOWNLOAD_PAUSE = "3";
private static final int DEFAULT_THREAD_COUNT = 4;//默认下载线程数
private String stateDownload = DOWNLOAD_INIT;//当前线程状态
private Thread[] mThreads;
private int CurrentProgress;//当前总共下载的大小
private int finishThread = 0;//记录完成下载的线程数
private Context context;
private String loadUrl;//网络获取的url
private String filePath;//下载到本地的path
private int threadCount = DEFAULT_THREAD_COUNT;//下载线程数
private DownloadListener mDownloadListener;
private final int SUCCESS = 1;
private final int FAILURE = 0;
public void setOnDownloadListener(DownloadListener downloadListener){
this.mDownloadListener = downloadListener;
}
interface DownloadListener{
//返回当前下载进度的百分比
void getProgress(int progress);
void onComplete();
void onFailer();
}
public DownloadFile(Context context, String loadUrl, String filePath){
this(context, loadUrl, filePath, DEFAULT_THREAD_COUNT, null);
}
public DownloadFile(Context context, String loadUrl, String filePath, DownloadListener downloadListener){
this(context, loadUrl, filePath, DEFAULT_THREAD_COUNT, downloadListener);
}
public DownloadFile(Context context, String loadUrl, String filePath, int threadCount){
this(context, loadUrl, filePath, threadCount, null);
}
public DownloadFile(Context context, String loadUrl, String filePath, int threadCount, DownloadListener downloadListener){
this.context = context;
this.loadUrl = loadUrl;
this.filePath = filePath;
this.threadCount = threadCount;
this.mDownloadListener = downloadListener;
}
private static Handler handler = new Handler(){
@Override
public void handlerMessage(Message msg){
if(msg.what == SUCCESS){
mDownloadListener.onComplete();
}else if(msg.what == FAILURE){
mDownloadListener.onFailer;
}else{
mDownloadListener.getProgress(msg.what);
}
}
}
protected void onPause(){
if(mThreads != null){
stateDownload = DOWNLOAD_PAUSE;
}
}
//继续下载
protected void onStart(){
if(mThreads != null){
synchronized(DOWNLOAD_PAUSE){
stateDownload = DOWNLOAD_ING;
DOWNLOAD_PAUSE.notifyAll();
}
}
}
protected void onDestroy(){
if(mThreads != null){
mThreads = null;
}
}
//取消下载
protected void cancel(){
if(mThreads != null){
//若线程处于等待状态,则while循环处于阻塞状态,无法跳出循环,必须先唤醒线程,才能执行取消任务
if(stateDownload.equals(DOWNLOAD_PAUSE))
onStart();
for(Thread td : mThreads){
((DownloadThead) td).cancel();
}
}
}
public void download(){
//在线程中运行,防止anr
Thread t = new Thread(){
@Override
public void run(){
//初始化数据
if(mThreads == null)
mThreads = new Thread[threadCount];
try{
URL url= new URL(loadUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
conn.setConnectionTime(5000);
//请求成功,根据文件大小开始分多线程下载
if(conn.getResponse() == 200){
int length = conn.getContentLength();
File file = new File(filePath);
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
raf.setLength(length);
raf.close();
//计算各个线程下载的数据段
int blockLength = length / threadCount;
for(int i = 0; i < threadCount; i++){
int startIndex = i * blockLength;
int endIndex = (i + 1) * blockLength - 1;
if(i == threadCount - 1){
endIndex = length - 1;
}
mThreads[i] = new DownloadThead(startIndex, endIndex, i);
mThreads[i].start();
}
}else{
handler.sendEmptyMessage(SUCCESS);
}
}catch(Exception e){
e.printStackTrace();
handler.sendEmptyMessage(SUCCESS);
}
}
};
t.start();
}
class DownloadThead extends Thread{
private boolean isGon = true;//是否继续下载
private int startIndex;//开始下载点
private int endIndex;//结束下载点
private int threadId;//当前线程的ID
public DownloadThead(int startIndex, int endIndex, int threadId){
super();
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
}
@Override
public void run(){
URL url = null;
try{
File fileProgress = new File(Environment.getExternalStorageDireactory(), threadId+".txt");
//判断存储下载进度的临时文件是否存在
if(fileProgress.exists()){
FileInputStream fis = new FileInputStream(fileProgress);
BufferReader br = new BufferReader(new InputStreamReader(fis));
//从下载进度的临时文件中读取上一次下载的总进度,然后和原来文本的开始位置相加,得到新的下载位置
int lastProgress = Integer.paseInt(br.readLine());
//把上次下载的进度显示到进度条,更新进度条
startIndex += lastProgress;
CurrentProgress += lastProgress;
//主线程刷新文本进度
handler.sendEmptyMessage(CurrentProgress);
fis.close();
}
url = new URL(loadUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
conn.setConntionTimeout(5000);
//设置请求数据的区间
conn.setRequestProperty("Range", "bytes="+startIndex + "-" + endIndex);
//若请求头加上Range这个参数,则返回状态码为206,而不是200
if(conn.getResponseCode() == 206){
InputStream is = conn.getInputStream();
byte[] b = new byte[1024];
int len = 0;
int total = 0;
File file = new File(filePath);
//拿到临时文件的引用
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
//更新文件的写入位置,startIndex
raf.seek(startIndex);
while((len = is.read(b)) != -1){
//是否继续下载
if(!isGon)
break;
raf.write(b, 0 ,len);
if(mDownloadListener != null){
total += len;
CurrentProgress +=len;
//主线程刷新文本进度
handler.sendEmptyMessage(CurrentProgress);
}
//生成一个专门记录下载进度的临时文件
RandomAccessFile fileProgressRaf = new RandomAccessFile(fileProgress, "rwd");
//每一次读取流里面的数据以后,把当前线程下载的总进度写入临时文件中
fileProgressRaf.write((total + "").getByte());
fileProgressRaf.close();
synchronized(DOWNLOAD_PAUSE){
if(stateDownload.equals(DOWNLOAD_PAUSE)){
DOWNLOAD_PAUSE.wait();
}
}
}
handler.sendEmptyMessage(SUCCESS);
raf.close();
//条线程下载完成以后,清理临时文件
finishThread ++;
//线程安全
synchronized(loadUrl){
if(finishThread == threadCount){
for(int i = 0; i < threadCount; i++){
File fileFinish = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
fileFinish.delete();
}
finishThread = 0;
}
}
}
handler.sendEmptyMessage(FAILURE);
}catch(Exception e){
e.printStackTrace();
handler.sendEmptyMessage(FAILURE);
}
}
public void cancel(){
isGon = false;
}
}
}
MainActivity.java
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
DownLoadFile downLoadFile;
private String loadUrl = "http://gdown.baidu.com/data/wisegame/d2fbbc8e64990454/wangyiyunyinle_87.apk";
private String filePath = Environment.getExternalStorageDirectory()+"/"+"网易云音乐.apk";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tvprogress = (TextView) findViewById(R.id.tv_progress);
downLoadFile = new DownLoadFile(this,loadUrl, filePath, 3);
downLoadFile.setOnDownLoadListener(new DownLoadFile.DownLoadListener() {
@Override
public void getProgress(int progress) {
tvprogress.setText("当前进度 :"+progress+" %");
}
@Override
public void onComplete() {
Toast.makeText(MainActivity.this,"下载完成",Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure() {
Toast.makeText(MainActivity.this,"下载失败",Toast.LENGTH_SHORT).show();
}
});
findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
downLoadFile.downLoad();
}
});
findViewById(R.id.bt_pause).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
downLoadFile.onPause();
}
});
findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
downLoadFile.onStart();
}
});
findViewById(R.id.bt_cancel).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
downLoadFile.cancel();
}
});
}
@Override
protected void onDestroy() {
downLoadFile.onDestroy();
super.onDestroy();
}
}