欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android实现多线程下载文件的方法

程序员文章站 2023-11-12 09:34:04
本文实例讲述了android实现多线程下载文件的方法。分享给大家供大家参考。具体如下: 多线程下载大概思路就是通过range 属性实现文件分段,然后用randomacce...

本文实例讲述了android实现多线程下载文件的方法。分享给大家供大家参考。具体如下:

多线程下载大概思路就是通过range 属性实现文件分段,然后用randomaccessfile 来读写文件,最终合并为一个文件

首先看下效果图:

Android实现多线程下载文件的方法

创建工程 threaddemo

首先布局文件 threaddemo.xml

<?xml version="1.0" encoding="utf-8"?> 
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" 
  android:orientation="vertical" 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent" 
  > 
<textview  
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"  
  android:text="下载地址" 
  /> 
<textview 
  android:id="@+id/downloadurl" 
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"  
  android:lines="5" 
  /> 
<textview  
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"  
  android:text="线程数" 
  /> 
<edittext 
  android:id="@+id/downloadnum" 
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"  
  /> 
<progressbar 
  android:id="@+id/downloadprogressbar" 
  android:layout_width="fill_parent"  
  style="?android:attr/progressbarstylehorizontal" 
  android:layout_height="wrap_content"  
  /> 
<textview 
  android:id="@+id/downloadinfo" 
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"  
  android:text="下载进度 0" 
  /> 
<button 
  android:id="@+id/downloadbutton" 
  android:layout_width="wrap_content"  
  android:layout_height="wrap_content"  
  android:text="开始下载" 
  /> 
</linearlayout>

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"  android:orientation="vertical" android:layout_width="fill_parent"  android:layout_height="fill_parent"  >
<textview   android:layout_width="fill_parent"   android:layout_height="wrap_content" android:text="下载地址"  />
<textviewandroid:id="@+id/downloadurl"android:layout_width="fill_parent" android:layout_height="wrap_content" android:lines="5"/>
<textview   android:layout_width="fill_parent"   android:layout_height="wrap_content" android:text="线程数"  />
<edittextandroid:id="@+id/downloadnum"android:layout_width="fill_parent" android:layout_height="wrap_content" />
<progressbarandroid:id="@+id/downloadprogressbar"android:layout_width="fill_parent" style="?android:attr/progressbarstylehorizontal"  android:layout_height="wrap_content" />
<textviewandroid:id="@+id/downloadinfo"android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="下载进度 0"/>
<buttonandroid:id="@+id/downloadbutton"android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="开始下载"/>
</linearlayout> 

主界面 acitivity

public class threaddownloaddemo extends activity { 
  private textview downloadurl; 
  private edittext downloadnum; 
  private button downloadbutton; 
  private progressbar downloadprogressbar; 
  private textview downloadinfo; 
  private int downloadedsize = 0; 
  private int filesize = 0; 
  private long downloadtime; 
  @override 
  public void oncreate(bundle savedinstancestate) { 
    super.oncreate(savedinstancestate); 
    setcontentview(r.layout.threaddemo); 
    downloadurl = (textview) findviewbyid(r.id.downloadurl); 
    downloadurl.settext("http://file16.top100.cn/201105110911/aa5cc27cbe34deb50a194581d1300881/special_323149/%e8%8d%b7%e5%a1%98%e6%9c%88%e8%89%b2.mp3"); 
    downloadnum = (edittext) findviewbyid(r.id.downloadnum); 
    downloadinfo = (textview) findviewbyid(r.id.downloadinfo); 
    downloadbutton = (button) findviewbyid(r.id.downloadbutton); 
    downloadprogressbar = (progressbar) findviewbyid(r.id.downloadprogressbar); 
    downloadprogressbar.setvisibility(view.visible); 
    downloadprogressbar.setmax(100); 
    downloadprogressbar.setprogress(0); 
    downloadbutton.setonclicklistener(new onclicklistener() { 
      public void onclick(view v) { 
        download(); 
        downloadtime = systemclock.currentthreadtimemillis(); 
      } 
    }); 
  } 
  private void download() { 
    // 获取sd卡目录  
    string dowloaddir = environment.getexternalstoragedirectory() 
        + "/threaddemodownload/"; 
    file file = new file(dowloaddir); 
    //创建下载目录  
    if (!file.exists()) { 
      file.mkdirs(); 
    } 
    //读取下载线程数,如果为空,则单线程下载  
    int downloadtn = integer.valueof("".equals(downloadnum.gettext() 
        .tostring()) ? "1" : downloadnum.gettext().tostring()); 
    string filename = "hetang.mp3"; 
    //开始下载前把下载按钮设置为不可用  
    downloadbutton.setclickable(false); 
    //进度条设为0  
    downloadprogressbar.setprogress(0); 
    //启动文件下载线程  
    new downloadtask("http://file16.top100.cn/201105110911/aa5cc27cbe34deb50a194581d1300881/special_323149/%e8%8d%b7%e5%a1%98%e6%9c%88%e8%89%b2.mp3", integer 
        .valueof(downloadtn), dowloaddir + filename).start(); 
  } 
  handler handler = new handler() { 
    @override 
    public void handlemessage(message msg) { 
      //当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息  
      int progress = (double.valueof((downloadedsize * 1.0 / filesize * 100))).intvalue(); 
      if (progress == 100) { 
        downloadbutton.setclickable(true); 
        downloadinfo.settext("下载完成!"); 
        dialog mdialog = new alertdialog.builder(threaddownloaddemo.this) 
          .settitle("提示信息") 
          .setmessage("下载完成,总用时为:"+(systemclock.currentthreadtimemillis()-downloadtime)+"毫秒") 
          .setnegativebutton("确定", new dialoginterface.onclicklistener(){ 
            @override 
            public void onclick(dialoginterface dialog, int which) { 
              dialog.dismiss(); 
            } 
          }) 
          .create(); 
        mdialog.show(); 
      } else { 
        downloadinfo.settext("当前进度:" + progress + "%"); 
      } 
      downloadprogressbar.setprogress(progress); 
    } 
  }; 
  public class downloadtask extends thread { 
    private int blocksize, downloadsizemore; 
    private int threadnum = 5; 
    string urlstr, threadno, filename; 
    public downloadtask(string urlstr, int threadnum, string filename) { 
      this.urlstr = urlstr; 
      this.threadnum = threadnum; 
      this.filename = filename; 
    } 
    @override 
    public void run() { 
      filedownloadthread[] fds = new filedownloadthread[threadnum]; 
      try { 
        url url = new url(urlstr); 
        urlconnection conn = url.openconnection(); 
        //防止返回-1  
        inputstream in = conn.getinputstream(); 
        //获取下载文件的总大小  
        filesize = conn.getcontentlength(); 
        log.i("bb", "======================filesize:"+filesize); 
        //计算每个线程要下载的数据量  
        blocksize = filesize / threadnum; 
        // 解决整除后百分比计算误差  
        downloadsizemore = (filesize % threadnum); 
        file file = new file(filename); 
        for (int i = 0; i < threadnum; i++) { 
          log.i("bb", "======================i:"+i); 
          //启动线程,分别下载自己需要下载的部分  
          filedownloadthread fdt = new filedownloadthread(url, file, i * blocksize, (i + 1) * blocksize - 1); 
          fdt.setname("thread" + i); 
          fdt.start(); 
          fds[i] = fdt; 
        } 
        boolean finished = false; 
        while (!finished) { 
          // 先把整除的余数搞定  
          downloadedsize = downloadsizemore; 
          finished = true; 
          for (int i = 0; i < fds.length; i++) { 
            downloadedsize += fds[i].getdownloadsize(); 
            if (!fds[i].isfinished()) { 
              finished = false; 
            } 
          } 
          handler.sendemptymessage(0); 
          //线程暂停一秒  
          sleep(1000); 
        } 
      } catch (exception e) { 
        e.printstacktrace(); 
      } 
    } 
  } 
} 
public class threaddownloaddemo extends activity {
private textview downloadurl;
private edittext downloadnum;
private button downloadbutton;
private progressbar downloadprogressbar;
private textview downloadinfo;
private int downloadedsize = 0;
private int filesize = 0;
private long downloadtime;
@overridepublic void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
setcontentview(r.layout.threaddemo);
downloadurl = (textview) findviewbyid(r.id.downloadurl);
downloadurl.settext("http://file16.top100.cn/201105110911/aa5cc27cbe34deb50a194581d1300881/special_323149/%e8%8d%b7%e5%a1%98%e6%9c%88%e8%89%b2.mp3");
downloadnum = (edittext) findviewbyid(r.id.downloadnum);
downloadinfo = (textview) findviewbyid(r.id.downloadinfo);
downloadbutton = (button) findviewbyid(r.id.downloadbutton);
downloadprogressbar = (progressbar) findviewbyid(r.id.downloadprogressbar);
downloadprogressbar.setvisibility(view.visible);
downloadprogressbar.setmax(100);
downloadprogressbar.setprogress(0);
downloadbutton.setonclicklistener(new onclicklistener() {
public void onclick(view v) {download();
downloadtime = systemclock.currentthreadtimemillis();
}
}
);
}
private void download() {// 获取sd卡目录
string dowloaddir = environment.getexternalstoragedirectory()+ "/threaddemodownload/";
file file = new file(dowloaddir);
//创建下载目录
if (!file.exists()) {file.mkdirs();
}//读取下载线程数,如果为空,则单线程下载
int downloadtn = integer.valueof("".equals(downloadnum.gettext().tostring()) ? "1" : downloadnum.gettext().tostring());
string filename = "hetang.mp3";
//开始下载前把下载按钮设置为不可用
downloadbutton.setclickable(false);
//进度条设为0
downloadprogressbar.setprogress(0);
//启动文件下载线程
new downloadtask("http://file16.top100.cn/201105110911/aa5cc27cbe34deb50a194581d1300881/special_323149/%e8%8d%b7%e5%a1%98%e6%9c%88%e8%89%b2.mp3", integer.valueof(downloadtn), dowloaddir + filename).start();
}
handler handler = new handler() {@overridepublic void handlemessage(message msg) {
//当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息
int progress = (double.valueof((downloadedsize * 1.0 / filesize * 100))).intvalue();
if (progress == 100) {downloadbutton.setclickable(true);
downloadinfo.settext("下载完成!");
dialog mdialog = new alertdialog.builder(threaddownloaddemo.this).settitle("提示信息").setmessage("下载完成,总用时为:"+(systemclock.currentthreadtimemillis()-downloadtime)+"毫秒").setnegativebutton("确定", new dialoginterface.onclicklistener(){@overridepublic void onclick(dialoginterface dialog, int which) {dialog.dismiss();
}}).create();
mdialog.show();
} else {
downloadinfo.settext("当前进度:" + progress + "%");
}
downloadprogressbar.setprogress(progress);
}
}; 
public class downloadtask extends thread {private int blocksize, downloadsizemore;
private int threadnum = 5;
string urlstr, threadno, filename;
public downloadtask(string urlstr, int threadnum, string filename) {
this.urlstr = urlstr;
this.threadnum = threadnum;
this.filename = filename;
}
@overridepublic void run() {
filedownloadthread[] fds = new filedownloadthread[threadnum];
try {url url = new url(urlstr);
urlconnection conn = url.openconnection();
//防止返回-1
inputstream in = conn.getinputstream();
//获取下载文件的总大小
filesize = conn.getcontentlength();
log.i("bb", "======================filesize:"+filesize);
//计算每个线程要下载的数据量
blocksize = filesize / threadnum;
// 解决整除后百分比计算误差
downloadsizemore = (filesize % threadnum);
file file = new file(filename);
for (int i = 0; i < threadnum; i++) {
log.i("bb", "======================i:"+i);
//启动线程,分别下载自己需要下载的部分
filedownloadthread fdt = new filedownloadthread(url, file, i * blocksize, (i + 1) * blocksize - 1);
fdt.setname("thread" + i);
fdt.start();
fds[i] = fdt;
}
boolean finished = false;
while (!finished) {
// 先把整除的余数搞定
downloadedsize = downloadsizemore;
finished = true;
for (int i = 0; i < fds.length; i++) {
downloadedsize += fds[i].getdownloadsize();
if (!fds[i].isfinished()) {
finished = false;
}
}
handler.sendemptymessage(0);
//线程暂停一秒sleep(1000);
}
}
catch (exception e) {
e.printstacktrace();
}
}
}
} 

这里启动线程将文件分割为几个部分,每一个部分再启动一个线程去下载数据
下载文件的线程

public class filedownloadthread extends thread{ 
  private static final int buffer_size=1024; 
  private url url; 
  private file file; 
  private int startposition; 
  private int endposition; 
  private int curposition; 
  //标识当前线程是否下载完成  
  private boolean finished=false; 
  private int downloadsize=0; 
  public filedownloadthread(url url,file file,int startposition,int endposition){ 
    this.url=url; 
    this.file=file; 
    this.startposition=startposition; 
    this.curposition=startposition; 
    this.endposition=endposition; 
  } 
  @override 
  public void run() { 
    bufferedinputstream bis = null; 
    randomaccessfile fos = null;                         
    byte[] buf = new byte[buffer_size]; 
    urlconnection con = null; 
    try { 
      con = url.openconnection(); 
      con.setallowuserinteraction(true); 
      //设置当前线程下载的起止点  
      con.setrequestproperty("range", "bytes=" + startposition + "-" + endposition); 
      log.i("bb", thread.currentthread().getname()+" bytes=" + startposition + "-" + endposition); 
      //使用java中的randomaccessfile 对文件进行随机读写操作  
      fos = new randomaccessfile(file, "rw"); 
      //设置写文件的起始位置  
      fos.seek(startposition); 
      bis = new bufferedinputstream(con.getinputstream());  
      //开始循环以流的形式读写文件  
      while (curposition < endposition) { 
        int len = bis.read(buf, 0, buffer_size);         
        if (len == -1) { 
          break; 
        } 
        fos.write(buf, 0, len); 
        curposition = curposition + len; 
        if (curposition > endposition) { 
          downloadsize+=len - (curposition - endposition) + 1; 
        } else { 
          downloadsize+=len; 
        } 
      } 
      //下载完成设为true  
      this.finished = true; 
      bis.close(); 
      fos.close(); 
    } catch (ioexception e) { 
      e.printstacktrace(); 
    } 
  } 
  public boolean isfinished(){ 
    return finished; 
  } 
  public int getdownloadsize() { 
    return downloadsize; 
  } 
} 
public class filedownloadthread extends thread{
private static final int buffer_size=1024;
private url url;
private file file;
private int startposition;
private int endposition;
private int curposition;//标识当前线程是否下载完成
private boolean finished=false;
private int downloadsize=0;
public filedownloadthread(url url,file file,int startposition,int endposition){
this.url=url;
this.file=file;
this.startposition=startposition;
this.curposition=startposition;
this.endposition=endposition;
}
@overridepublic void run() {
bufferedinputstream bis = null;
randomaccessfile fos = null;
byte[] buf = new byte[buffer_size];
urlconnection con = null;
try {
con = url.openconnection();
con.setallowuserinteraction(true);
//设置当前线程下载的起止点
con.setrequestproperty("range", "bytes=" + startposition + "-" + endposition);
log.i("bb", thread.currentthread().getname()+" bytes=" + startposition + "-" + endposition);
//使用java中的randomaccessfile 对文件进行随机读写操作
fos = new randomaccessfile(file, "rw");
//设置写文件的起始位置
fos.seek(startposition);
bis = new bufferedinputstream(con.getinputstream());
//开始循环以流的形式读写文件
while (curposition < endposition) {
int len = bis.read(buf, 0, buffer_size);
if (len == -1) {
break;
}
fos.write(buf, 0, len);
curposition = curposition + len;
if (curposition > endposition) {
downloadsize+=len - (curposition - endposition) + 1;
} else {
downloadsize+=len;
}
}
//下载完成设为true
this.finished = true;
bis.close();
fos.close();
} catch (ioexception e) {
e.printstacktrace();
}
}
public boolean isfinished(){return finished;}
public int getdownloadsize() {return downloadsize;}
}

这里通过randomaccessfile 的seek方法定位到相应的位置 并实时记录下载量
当然这里需要联网和访问sd卡 所以要加上相应的权限

<uses-permission android:name="android.permission.internet" /> 
<uses-permission android:name="android.permission.write_external_storage"></uses-permission> 
<uses-permission android:name="android.permission.internet" /><uses-permission android:name="android.permission.write_external_storage"></uses-permission>

这样就ok了 下面可以看看断点续传的问题了。有待测试~~

希望本文所述对大家的android程序设计有所帮助。