热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

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

这篇文章主要介绍了Android实现多线程下载文件的方法,以实例形式较为详细的分析了Android多线程文件传输及合并等操作的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下

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

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

首先看下效果图:

创建工程 ThreadDemo

首先布局文件 threaddemo.xml

<&#63;xml version="1.0" encoding="utf-8"&#63;> 
 
 
 
 
 
 
 
<&#63;xml version="1.0" encoding="utf-8"&#63;>








 

主界面 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()) &#63; "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 

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

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) { 
          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) {
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卡 所以要加上相应的权限

 
 


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

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


推荐阅读
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • 本文介绍了在使用MSXML解析XML文件时出现DTD禁用问题的解决方案。通过代码示例和错误信息获取方法,解释了默认情况下DTD是禁用的,以及如何启用DTD的方法。此外,还提到了网上关于该问题的信息相对较少,因此本文提供了解决方案以供参考。 ... [详细]
author-avatar
wangxuan1992_273_361
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有