1.断点续传功能需要服务器支持
2.开启线程池进行任务的加载
3.支持进度的回调
4.支持终止正在进行和未进行的下载任务
5.调用简单
6.对服务端是否支持断点续传的判断机制不够完善,使用者需自己确定是否支持断点续传
单个任务下载DownloadTask
多个任务下载DownloadTaskPool
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:onClick="onClickStart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="开始" />
<Button
android:onClick="onClickRestart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="继续" />
<Button
android:onClick="onClickStop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="停止" />
<ProgressBar
android:id="@+id/progressBar1"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ProgressBar
android:id="@+id/progressBar2"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ProgressBar
android:id="@+id/progressBar3"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ProgressBar
android:id="@+id/progressBar4"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
public class BaseActivity extends Activity {
private DownloadTask task1;
private ProgressBar progressBar1;
private ProgressBar progressBar2;
private ProgressBar progressBar3;
private ProgressBar progressBar4;
private DownloadTaskPool taskPool;
private DownloadTask task2;
private DownloadTask task3;
private DownloadTask task4;
private HashMap<Object, ProgressBar> barMap = new HashMap<Object, ProgressBar>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base);
progressBar1 = (ProgressBar) findViewById(R.id.progressBar1);
progressBar1.setMax(100);
progressBar2 = (ProgressBar) findViewById(R.id.progressBar2);
progressBar2.setMax(100);
progressBar3 = (ProgressBar) findViewById(R.id.progressBar3);
progressBar3.setMax(100);
progressBar4 = (ProgressBar) findViewById(R.id.progressBar4);
progressBar4.setMax(100);
task1 = new DownloadTask(
"http://www.windows7en.com/uploads/140829/2010060910062251.jpg",
Environment.getExternalStorageDirectory() + "/test01.jpg", true);
task2 = new DownloadTask(
"http://pubcn.net/Photo/UploadPhotos/200711/20071109020411176.jpg",
Environment.getExternalStorageDirectory() + "/test02.jpg", true);
task3 = new DownloadTask(
"http://pubcn.net/Photo/UploadPhotos/200711/20071106122927651.jpg",
Environment.getExternalStorageDirectory() + "/test03.jpg", true);
task4 = new DownloadTask(
"http://pubcn.net/Photo/UploadPhotos/200711/20071109013917774.jpg",
Environment.getExternalStorageDirectory() + "/test04.jpg", true);
barMap.put(task1, progressBar1);
barMap.put(task2, progressBar2);
barMap.put(task3, progressBar3);
barMap.put(task4, progressBar4);
taskPool = new DownloadTaskPool() {
@Override
public void onTaskStateChanged(TaskState state, DownloadTask task) {
switch (state) {
case START:
Toast.makeText(BaseActivity.this, "开始下载",
Toast.LENGTH_SHORT).show();
break;
case STOP:
Toast.makeText(BaseActivity.this, "终止下载",
Toast.LENGTH_SHORT).show();
break;
case FAIL:
Toast.makeText(BaseActivity.this, "下载失败",
Toast.LENGTH_SHORT).show();
break;
case SUCCEED:
Toast.makeText(BaseActivity.this, "下载完成",
Toast.LENGTH_SHORT).show();
break;
}
}
@Override
public void onProgressIncreased(long current, long total, DownloadTask task) {
ProgressBar pb = barMap.get(task);
if(0!=total){
pb.setProgress((int) (current*100/total));
}
}
};
}
public void onClickStart(View v) {
taskPool.addTask(task1);
taskPool.addTask(task2);
taskPool.addTask(task3);
taskPool.addTask(task4);
}
public void onClickStop(View v) {
taskPool.removeTask(task1);
taskPool.removeTask(task2);
taskPool.removeTask(task3);
taskPool.removeTask(task4);
}
public void onClickRestart(View v) {
taskPool.addTask(task1);
taskPool.addTask(task2);
taskPool.addTask(task3);
taskPool.addTask(task4);
}
}
public enum TaskState {
SUCCEED,
FAIL,
STOP,
START
}
public class DownloadTask implements Runnable{
private static final String TMP_SUFFIX = ".tmp";
/**
* 存放下载后的文件路径
*/
private String filePath;
/**
*
*/
private String tmpFilePath;
/**
* 图片网址
*/
private String url;
private long transferedBytes;
private long totalBytes;
private boolean isCanceled;
private Thread thread;
private DownloadTaskCallBack callBack;
/**
* 是否支持断点续传
*/
private boolean isBrokenPointResumeAllowed;
/**
*
* @param url 要下载的文件的URL地址
* @param filePath 下载后的文件的存储路径
* @param allowBrokenPointResume true 支持断点续传,要求服务器支持才行,否则下载的文件有问题。 false 不支持断点续传
*/
public DownloadTask(String url, String filePath, boolean allowBrokenPointResume){
this.url = url;
this.filePath = filePath;
this.tmpFilePath = filePath+TMP_SUFFIX;
this.isBrokenPointResumeAllowed = allowBrokenPointResume;
}
public void run() {
if(isCanceled){
if(null!=callBack){
callBack.onTaskStateChanged(TaskState.START, this);
callBack.onProgressIncreased(100, 100, this);
callBack.onTaskStateChanged(TaskState.SUCCEED, this);
}
return;
}
if(null!=callBack){
callBack.onTaskStateChanged(TaskState.START, this);
}
boolean result = false;
try {
FileOutputStream fos = null;
HttpClient client = new DefaultHttpClient();
HttpGet getRequest = new HttpGet(url);
File tmpFile = new File(tmpFilePath);
if(isBrokenPointResumeAllowed && tmpFile.exists()){
FileInputStream fis = new FileInputStream(tmpFile);
transferedBytes = fis.available();
fis.close();
//请求断点续传
Header header = new BasicHeader("Range", "bytes=" + transferedBytes+'-');
getRequest.addHeader(header);
}
fos = new FileOutputStream(tmpFile, isBrokenPointResumeAllowed);
HttpEntity entity = client.execute(getRequest).getEntity();
Log.e("", entity.toString());
totalBytes = entity.getContentLength();
BufferedInputStream bis = new BufferedInputStream(entity.getContent(), 1024);
byte[] buffer = new byte[1024];
int n = 0;
do{
if(isCanceled){
fos.close();
getRequest.abort();
callBack.onTaskStateChanged(TaskState.STOP, this);
thread = null;
return;
}
fos.write(buffer, 0, n);
transferedBytes += n;
if(null!=callBack){
callBack.onProgressIncreased(transferedBytes, totalBytes, this);
}
if(transferedBytes>=totalBytes){
break;
}
n = bis.read(buffer);
}while(n!=-1);
fos.close();
result = tmpFile.renameTo(new File(filePath));
getRequest.abort();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
callBack.onTaskStateChanged(result ? TaskState.SUCCEED : TaskState.FAIL , this);
thread = null;
}
/**
* 单独使用时设置下载的回调
* @param callBack
*/
public void setCallBack(DownloadTaskCallBack callBack) {
this.callBack = callBack;
}
public boolean fileExists(){
return new File(filePath).exists();
}
public void start() {
isCanceled = false;
if(null==thread){
transferedBytes = 0;
thread = new Thread(this);
thread.start();
}
}
public void abort() {
isCanceled = true;
}
void setActive(){
isCanceled = false;
}
DownloadTaskPool getBindedTaskPool(){
return bindedTaskPool;
}
void setBindedTaskPool(DownloadTaskPool taskPool){
this.bindedTaskPool = taskPool;
}
private DownloadTaskPool bindedTaskPool;
public long getTransferedBytes() {
return transferedBytes;
}
public long getTotalBytes() {
return totalBytes;
}
public String getUrl(){
return url;
}
public String getFilePath(){
return filePath;
}
}
public abstract class DownloadTaskPool {
final static int MSG_PROGRESS = 0;
final static int MSG_START = 1;
final static int MSG_STOP = 2;
final static int MSG_FAIL = 3;
final static int MSG_SUCCEED = 4;
/**
* 返回1解码成功,返回2下载成功,返回3解码失败,返回4下载失败
*/
private static Handler handler = new Handler() {
public void handleMessage(Message msg) {
DownloadTask task = (DownloadTask) msg.obj;
switch(msg.what){
case MSG_PROGRESS:
task.getBindedTaskPool().onProgressIncreased(task.getTransferedBytes(), task.getTotalBytes(), task);
break;
case MSG_START:
task.getBindedTaskPool().onTaskStateChanged(TaskState.START, task);
break;
case MSG_STOP:
task.getBindedTaskPool().onTaskStateChanged(TaskState.STOP, task);
break;
case MSG_FAIL:
task.getBindedTaskPool().onTaskStateChanged(TaskState.FAIL, task);
break;
case MSG_SUCCEED:
task.getBindedTaskPool().onTaskStateChanged(TaskState.SUCCEED, task);
break;
}
};
};
private DownloadTaskCallBack callBack = new DownloadTaskCallBack() {
@Override
public void onProgressIncreased(long current, long total, DownloadTask task) {
handler.removeMessages(MSG_PROGRESS, task);
Message msg = Message.obtain(handler);
msg.obj = task;
msg.sendToTarget();
}
@Override
public void onTaskStateChanged(TaskState state, DownloadTask task) {
Message msg = Message.obtain(handler);
msg.obj = task;
switch(state){
case START:
msg.what = MSG_START;
break;
case STOP:
msg.what = MSG_STOP;
break;
case FAIL:
msg.what = MSG_FAIL;
break;
case SUCCEED:
msg.what = MSG_SUCCEED;
break;
}
msg.sendToTarget();
}
};
private ExecutorService taskExecutor = Executors.newFixedThreadPool(3);
private HashSet<DownloadTask> taskSet = new HashSet<DownloadTask>();
public void addTask(DownloadTask task){
if(!taskSet.contains(task)){
if(task.fileExists()){
return;
}else{
task.setCallBack(callBack);
taskSet.add(task);
task.setBindedTaskPool(this);
task.setActive();
taskExecutor.execute(task);
}
}
}
public abstract void onProgressIncreased(long current, long total, DownloadTask task);
public abstract void onTaskStateChanged(TaskState state, DownloadTask task);
public void removeTask(DownloadTask task){
task.abort();
taskSet.remove(task);
}
public void shutDown(){
taskExecutor.shutdown();
for(DownloadTask task : taskSet){
task.abort();
}
}
}