今天有人问我这个问题了,然后就写了代码。代码加了很多注释,我就不赘述了。主要就是有一个线程队列,维护这些任务,这里没有用到Queue而是用List是考虑到显示的问题。线程类,任务类
package com.robert.my;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import android.os.Handler;
import android.os.Message;
/**
* @author Robert
* */
public class DownloadThread extends Thread{
/**开始下载*/
public final static int THREAD_BEGIN = 1;
/**下载结束*/
public final static int THREAD_FINISHED = 2;
//下载进度
private float percent = 0;
//下载路径
private URL url;
//下载的文件大小
private long fileLength;
//文件的保存路径
private String filePath;
//是否线程已启动
private boolean isStarted = false;
private Handler mHandler;
public DownloadThread(URL url, String filePath, Handler mHandler){
this.url = url;
this.filePath = filePath;
this.mHandler = mHandler;
}
/**开始下载任务*/
@Override
public void run() {
isStarted = true;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try{
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //建立一个远程连接句柄,此时尚未真正连接
conn.setConnectTimeout(5*1000); //设置连接超时时间为5秒
conn.setRequestMethod("GET"); //设置请求方式为GET
conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
conn.setRequestProperty("Charset", "UTF-8"); //设置客户端编码
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"); //设置用户代理
conn.setRequestProperty("Connection", "Keep-Alive"); //设置Connection的方式
conn.connect(); //和远程资源建立真正的连接,但尚无返回的数据流
fileLength = conn.getContentLength();
byte[] buffer = new byte[8096]; //下载的缓冲池为8KB
bis = new BufferedInputStream(conn.getInputStream());
bos = new BufferedOutputStream(new FileOutputStream(new File(filePath)));
long downloadLength = 0;//当前已下载的文件大小
int bufferLength = 0;
while(( bufferLength = bis.read(buffer) ) != -1){
bos.write(buffer, 0, bufferLength);
bos.flush();
//计算当前下载进度
downloadLength += bufferLength;
percent = downloadLength/fileLength;
}
//发送下载完毕的消息
Message msg = new Message();
msg.what = THREAD_FINISHED;
mHandler.sendMessage(msg);
}catch(Exception e){
e.printStackTrace();
//TODO:建议这里发送下载失败的消息
}finally{
try {
if(bis != null) {
bis.close();
}
if(bos != null){
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public URL getUrl() {
return url;
}
public float getPercent() {
return percent;
}
public boolean isStarted(){
return isStarted;
}
public void setHandler(Handler mHandler){
this.mHandler = mHandler;
}
}
Activity
package com.eric.download;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import com.robert.my.DownloadThread;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
/**
* @author Robert
* */
public class MultiActivity extends Activity{
//线程锁,如果对这个不懂,百度一下
private Lock lock = new ReentrantLock();
//任务集合
List<DownloadThread> threads = new ArrayList<DownloadThread>();
//任务状态的数据
List<Map<String,String>> data = new ArrayList<Map<String,String>>();
private EditText editText;
private ListView listView;
private Button button;
private int threadFinishedCount = 0;//已完成任务的数量
private int count = 0; //已添加多少个任务
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mylayout);
initViews();
}
/**
* 设置任务列表的数据并刷新显示任务列表
* */
private void showListView(){
SimpleAdapter adapter = new SimpleAdapter(this, data, android.R.layout.simple_list_item_2, new String[]{"count", "status"}, new int[]{
android.R.id.text1, android.R.id.text2
});
listView.setAdapter(adapter);
listView.invalidate();
}
/**
* 初始化界面元素
* */
private void initViews() {
editText = (EditText)findViewById(R.id.download_edt);
button = (Button)findViewById(R.id.download_btn);
listView = (ListView)findViewById(R.id.listview1);
button.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
try {
count++;
lock.lock();
threads.add(new DownloadThread(
new URL(editText.getText().toString()),"/mnt/sdcard/a" + count + ".html",myHandler));
lock.unlock();
Map<String,String> map = new HashMap<String,String>();
map.put("status", "等待下载");
map.put("count", "线程" + count);
data.add(map);
} catch (MalformedURLException e) {
e.printStackTrace();
}
showListView();
Message message = new Message();
message.what = DownloadThread.THREAD_BEGIN;
myHandler.sendMessage(message);
}
});
}
private Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case DownloadThread.THREAD_BEGIN:
lock.lock();
if(threads.size() <= count && threads.size() > threadFinishedCount){
if(!threads.get(threadFinishedCount).isStarted()){
//开始一个新的下载任务
threads.get(threadFinishedCount).start();
//设置显示当前任务状态为正在下载
data.get(threadFinishedCount).put("status", "下载中……");
showListView();
}
}else{
Toast.makeText(MultiActivity.this, "无任务了", Toast.LENGTH_LONG);
}
lock.unlock();
break;
case DownloadThread.THREAD_FINISHED:
lock.lock();
if(threads.size() >= threadFinishedCount){
//设置当前下载任务已完成
data.get(threadFinishedCount).put("status", "下载完成");
threadFinishedCount++;
//开始下一个任务
Message message = new Message();
message.what = DownloadThread.THREAD_BEGIN;
sendMessage(message);
showListView();
}
lock.unlock();
break;
}
}
};
}
xml布局很普通,简单显示一些数据而已
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<EditText android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/download_edt"
android:text="@string/url"
android:hint="输入下载地址"
/>
<Button android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="点击下载"
android:id="@+id/download_btn"
/>
<ListView android:layout_width="match_parent" android:layout_height="match_parent"
android:id="@+id/listview1"
></ListView>
</LinearLayout>
效果图