来源:网易云课堂android极客班第八次作业练习
练习内容: asynctask handler
多线程下载的原理
首先获取到目标文件的大小,然后在磁盘上申请一块空间用于保存目标文件,接着把目标文件分割成n份,分别创建线程下载.
获取目标文件的大小
//使用目标文件的下载链接作为发起网络请求
murl = new ;
//注意不是urlconnection, urlconnection是抽象类,httpurlconnection是它的子类
httpurlconnection urlconnection = (httpurlconnection) murl.openconnection();
urlconnection.setrequestmethod("get");
urlconnection.setconnecttimeout(5000);
//获取目标文件的大小
mcontentlength = urlconnection.getcontentlength();
在磁盘上申请一块空间,用于保存目标文件,这里用到了randomaccessfile类,该类的seek()方法能够非常方便的对文件进行指定位置的定位.
mfile = new file(environment.getexternalstoragedirectory(), getfilename(params[0]));
if (mfile.exists()) {//如果文件已经存在,删除
mfile.delete();
}
randomaccessfile randomfile = new randomaccessfile(mfile, "rw");
//设置文件大小
randomfile.setlength(mcontentlength);
分割文件,分别创建线程进行下载(只需要关注非注释内容)
int blocksize = mcontentlength / 3;
for (int i = 0; i < 3; i ) {
int begin = i * blocksize;
int end = (i 1) * blocksize - 1;
if (i == 2) {
end = mcontentlength;
}
//hashmap map = new hashmap<>();
//map.put("begin", begin);
//map.put("end", end);
//map.put("finished", 0);
//threadlist.add(map);
//new thread
new thread(new downloadthread(i, begin, end, mfile, murl)).start();
}
的原理
在每个线程进行下载的过程中,每次写入文件的时候,记录已经下载了多少内容,重新开始下载时,从上次结束的位置继续下载.
数据结构
使用hashmap存储该线程下载文件的起始位置,结束位置和已完成大小,并使用一个arraylist存储各线程数据
private list> threadlist = new arraylist<>();
hashmap map = new hashmap<>();
map.put("begin", begin);//开始位置
map.put("end", end);//结束位置
map.put("finished", 0);//已完成
发起网络请求时,指定起止位置
httpurlconnection urlconnection = (httpurlconnection) url.openconnection();
urlconnection.setrequestmethod("get");
//指定起止位置
urlconnection.setrequestproperty("range", "bytes=" begin "-" end);
下载时更新map中的finished字段的值
while ((len = is.read(buf)) != -1 && isdownloading) {
randomfile.write(buf, 0, len);
updateprogress(len);
//更新map中的finished字段的值
map.put("finished", map.get("finished") len);
}
再次开始下载时,更新每个线程的开始位置(即实例化downloadthread类时所需要的第二个参数)
for (int i = 0; i < threadlist.size(); i ) {
hashmap map = threadlist.get(i);
new thread(new downloadthread(i, map.get("begin") map.get("finished"), map.get("end"), mfile, murl)).start();
}
更新ui的操作
自定义handler
public static class downloadhandler extends android.os.handler {
public final weakreference mactivity;
public downloadhandler(mainactivity activity) {
mactivity = new weakreference(activity);
}
@override
public void handlemessage(message msg) {
super.handlemessage(msg);
mainactivity activity = mactivity.get();
switch (msg.what) {
case 0:
int progress = (int) msg.obj;
activity.getprogressbar().setprogress(progress);
if (progress == 100) {
// toast.maketext(activity, "下载成功",toast.length_short).show();
activity.getdownloadbutton().settext("下载成功");
}
}
}
}
更新ui的方法
//使用synchronized
synchronized private void updateprogress(int len) {
total = len;
int temp = total * 100 / mcontentlength;
mdownloadhandler.obtainmessage(0, temp).sendtotarget();
}
完整代码github地址:https://github.com/zhangbz/multithreadingdownloaddemo