当前位置: 移动技术网 > 移动技术>移动开发>Android > Android实现网络多线程文件下载

Android实现网络多线程文件下载

2019年07月24日  | 移动技术网移动技术  | 我要评论

实现原理

(1)首先获得下载文件的长度,然后设置本地文件的长度。

(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。

如:文件的长度为6m,线程数为3,那么,每条线程下载的数据长度为2m,每条线程开始下载的位置如下图所示:

(网上找的图)

例如10m大小,使用3个线程来下载,

线程下载的数据长度 (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4m,第三个线程下载长度为2m

下载开始位置:线程id*每条线程下载的数据长度 = ?

下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?

之前练习时的一个demo,不多说了,直接上代码吧,有关断点续传,需要使用数据库,不再加了,网上有很多成熟的项目可以直接用。

实例

mainapp:

package com.amos.app; 
import java.io.file; 
import java.io.ioexception; 
import java.net.malformedurlexception; 
import java.net.url; 
import java.net.urlconnection; 
import com.amos.download.r; 
import android.annotation.suppresslint; 
import android.app.activity; 
import android.os.bundle; 
import android.os.environment; 
import android.os.handler; 
import android.os.message; 
import android.util.log; 
import android.view.view; 
import android.view.view.onclicklistener; 
import android.widget.progressbar; 
import android.widget.textview; 
import android.widget.toast; 
/** 
* @author yangxiaolong 
* @2014-5-6 
*/ 
public class mainapp extends activity implements onclicklistener { 
private static final string tag = mainapp.class.getsimplename(); 
/** 显示下载进度textview */ 
private textview mmessageview; 
/** 显示下载进度progressbar */ 
private progressbar mprogressbar; 
@override 
protected void oncreate(bundle savedinstancestate) { 
super.oncreate(savedinstancestate); 
setcontentview(r.layout.progress_activity); 
findviewbyid(r.id.download_btn).setonclicklistener(this); 
mmessageview = (textview) findviewbyid(r.id.download_message); 
mprogressbar = (progressbar) findviewbyid(r.id.download_progress); 
} 
@override 
public void onclick(view v) { 
if (v.getid() == r.id.download_btn) { 
dodownload(); 
} 
} 
/** 
* 使用handler更新ui界面信息 
*/ 
@suppresslint("handlerleak") 
handler mhandler = new handler() { 
@override 
public void handlemessage(message msg) { 
mprogressbar.setprogress(msg.getdata().getint("size")); 
float temp = (float) mprogressbar.getprogress() 
/ (float) mprogressbar.getmax(); 
int progress = (int) (temp * 100); 
if (progress == 100) { 
toast.maketext(mainapp.this, "下载完成!", toast.length_long).show(); 
} 
mmessageview.settext("下载进度:" + progress + " %"); 
} 
}; 
/** 
* 下载准备工作,获取sd卡路径、开启线程 
*/ 
private void dodownload() { 
// 获取sd卡路径 
string path = environment.getexternalstoragedirectory() 
+ "/amosdownload/"; 
file file = new file(path); 
// 如果sd卡目录不存在创建 
if (!file.exists()) { 
file.mkdir(); 
} 
// 设置progressbar初始化 
mprogressbar.setprogress(0); 
// 简单起见,我先把url和文件名称写死,其实这些都可以通过httpheader获取到 
string downloadurl = "http://gdown.baidu.com/data/wisegame/91319a5a1dfae322/baidu_16785426.apk"; 
string filename = "baidu_16785426.apk"; 
int threadnum = 5; 
string filepath = path + filename; 
log.d(tag, "download file path:" + filepath); 
downloadtask task = new downloadtask(downloadurl, threadnum, filepath); 
task.start(); 
} 
/** 
* 多线程文件下载 
* 
* @author yangxiaolong 
* @2014-8-7 
*/ 
class downloadtask extends thread { 
private string downloadurl;// 下载链接地址 
private int threadnum;// 开启的线程数 
private string filepath;// 保存文件路径地址 
private int blocksize;// 每一个线程的下载量 
public downloadtask(string downloadurl, int threadnum, string fileptah) { 
this.downloadurl = downloadurl; 
this.threadnum = threadnum; 
this.filepath = fileptah; 
} 
@override 
public void run() { 
filedownloadthread[] threads = new filedownloadthread[threadnum]; 
try { 
url url = new url(downloadurl); 
log.d(tag, "download file http path:" + downloadurl); 
urlconnection conn = url.openconnection(); 
// 读取下载文件总大小 
int filesize = conn.getcontentlength(); 
if (filesize <= 0) { 
system.out.println("读取文件失败"); 
return; 
} 
// 设置progressbar最大的长度为文件size 
mprogressbar.setmax(filesize); 
// 计算每条线程下载的数据长度 
blocksize = (filesize % threadnum) == 0 ? filesize / threadnum 
: filesize / threadnum + 1; 
log.d(tag, "filesize:" + filesize + " blocksize:"); 
file file = new file(filepath); 
for (int i = 0; i < threads.length; i++) { 
// 启动线程,分别下载每个线程需要下载的部分 
threads[i] = new filedownloadthread(url, file, blocksize, 
(i + 1)); 
threads[i].setname("thread:" + i); 
threads[i].start(); 
} 
boolean isfinished = false; 
int downloadedallsize = 0; 
while (!isfinished) { 
isfinished = true; 
// 当前所有线程下载总量 
downloadedallsize = 0; 
for (int i = 0; i < threads.length; i++) { 
downloadedallsize += threads[i].getdownloadlength(); 
if (!threads[i].iscompleted()) { 
isfinished = false; 
} 
} 
// 通知handler去更新视图组件 
message msg = new message(); 
msg.getdata().putint("size", downloadedallsize); 
mhandler.sendmessage(msg); 
// log.d(tag, "current downloadsize:" + downloadedallsize); 
thread.sleep(1000);// 休息1秒后再读取下载进度 
} 
log.d(tag, " all of downloadsize:" + downloadedallsize); 
} catch (malformedurlexception e) { 
e.printstacktrace(); 
} catch (ioexception e) { 
e.printstacktrace(); 
} catch (interruptedexception e) { 
e.printstacktrace(); 
} 
} 
} 
}

filedownloadthread:

package com.amos.app; 
import java.io.bufferedinputstream; 
import java.io.file; 
import java.io.ioexception; 
import java.io.randomaccessfile; 
import java.net.url; 
import java.net.urlconnection; 
import android.util.log; 
/** 
* 文件下载类 
* 
* @author yangxiaolong 
* @2014-5-6 
*/ 
public class filedownloadthread extends thread { 
private static final string tag = filedownloadthread.class.getsimplename(); 
/** 当前下载是否完成 */ 
private boolean iscompleted = false; 
/** 当前下载文件长度 */ 
private int downloadlength = 0; 
/** 文件保存路径 */ 
private file file; 
/** 文件下载路径 */ 
private url downloadurl; 
/** 当前下载线程id */ 
private int threadid; 
/** 线程下载数据长度 */ 
private int blocksize; 
/** 
* 
* @param url:文件下载地址 
* @param file:文件保存路径 
* @param blocksize:下载数据长度 
* @param threadid:线程id 
*/ 
public filedownloadthread(url downloadurl, file file, int blocksize, 
int threadid) { 
this.downloadurl = downloadurl; 
this.file = file; 
this.threadid = threadid; 
this.blocksize = blocksize; 
} 
@override 
public void run() { 
bufferedinputstream bis = null; 
randomaccessfile raf = null; 
try { 
urlconnection conn = downloadurl.openconnection(); 
conn.setallowuserinteraction(true); 
int startpos = blocksize * (threadid - 1);//开始位置 
int endpos = blocksize * threadid - 1;//结束位置 
//设置当前线程下载的起点、终点 
conn.setrequestproperty("range", "bytes=" + startpos + "-" + endpos); 
system.out.println(thread.currentthread().getname() + " bytes=" 
+ startpos + "-" + endpos); 
byte[] buffer = new byte[1024]; 
bis = new bufferedinputstream(conn.getinputstream()); 
raf = new randomaccessfile(file, "rwd"); 
raf.seek(startpos); 
int len; 
while ((len = bis.read(buffer, 0, 1024)) != -1) { 
raf.write(buffer, 0, len); 
downloadlength += len; 
} 
iscompleted = true; 
log.d(tag, "current thread task has finished,all size:" 
+ downloadlength); 
} catch (ioexception e) { 
e.printstacktrace(); 
} finally { 
if (bis != null) { 
try { 
bis.close(); 
} catch (ioexception e) { 
e.printstacktrace(); 
} 
} 
if (raf != null) { 
try { 
raf.close(); 
} catch (ioexception e) { 
e.printstacktrace(); 
} 
} 
} 
} 
/** 
* 线程文件是否下载完毕 
*/ 
public boolean iscompleted() { 
return iscompleted; 
} 
/** 
* 线程下载文件长度 
*/ 
public int getdownloadlength() { 
return downloadlength; 
} 
}

效果图:


log控制台:

可以看到文件总大小、我们创建的5个线程每个负责下载的区间

sd卡:

关于android实现网络多线程文件下载小编就给大家介绍这么多,希望对大家有所帮助!同时也非常感谢大家一直以来对移动技术网网站的支持!

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网