android端实现断点续传下载---改进版

添加监听

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();
    }
}

猜你喜欢

转载自blog.csdn.net/augfun/article/details/88501061
今日推荐