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

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

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

首先看下效果图:

创建工程 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程序设计有所帮助。

(0)

相关推荐

  • Android中实现下载和解压zip文件功能代码分享

    本文提供了2段Android代码,实现了从Android客户端下载ZIP文件并且实现ZIP文件的解压功能,非常实用,有需要的Android开发者可以尝试一下. 下载: DownLoaderTask.java 复制代码 代码如下: package com.johnny.testzipanddownload; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; im

  • Android实现文件下载进度显示功能

    和大家一起分享一下学习经验,如何实现Android文件下载进度显示功能,希望对广大初学者有帮助. 先上效果图: 上方的蓝色进度条,会根据文件下载量的百分比进行加载,中部的文本控件用来现在文件下载的百分比,最下方的ImageView用来展示下载好的文件,项目的目的就是动态向用户展示文件的下载量. 下面看代码实现:首先是布局文件: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xm

  • Android通过startService实现文件批量下载

    关于startService的基本使用概述及其生命周期可参见<Android中startService基本使用方法概述>. 本文通过批量下载文件的简单示例,演示startService以及stopService(startId)的使用流程,具体内容如下 系统界面如下: 界面很简单,就一个按钮"批量下载文章",通过该Activity上的按钮启动DownloadService. DownloadService是用来进行下载CSDN上博客文章的服务,代码如下: package c

  • Android使用缓存机制实现文件下载及异步请求图片加三级缓存

    首先给大家介绍Android使用缓存机制实现文件下载 在下载文件或者在线浏览文件时,或者为了保证文件下载的正确性,需要使用缓存机制,常使用SoftReference来实现. SoftReference的特点是它的一个实例保存对一个Java对象的软引用,该软引用的存在不妨碍垃圾收集线程对该Java对象的回收.也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用.另外

  • Android 将文件下载到指定目录的实现代码

    废话不多说了额,直接给大家贴代码了,具体代码如下所示: /** * 下载指定路径的文件,并写入到指定的位置 * * @param dirName * @param fileName * @param urlStr * @return 返回0表示下载成功,返回1表示下载出错 */ public int downloadFile(String dirName, String fileName, String urlStr) { OutputStream output = null; try { //

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

    本文实例讲述了Android实现多线程下载文件的方法.分享给大家供大家参考.具体如下: 多线程下载大概思路就是通过Range 属性实现文件分段,然后用RandomAccessFile 来读写文件,最终合并为一个文件 首先看下效果图: 创建工程 ThreadDemo 首先布局文件 threaddemo.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo

  • Python多线程下载文件的方法

    本文实例讲述了Python多线程下载文件的方法.分享给大家供大家参考.具体实现方法如下: import httplib import urllib2 import time from threading import Thread from Queue import Queue from time import sleep proxy = 'your proxy'; opener = urllib2.build_opener( urllib2.ProxyHandler({'http':proxy

  • Android通过SOCKET下载文件的方法

    本文实例讲述了Android通过SOCKET下载文件的方法.分享给大家供大家参考,具体如下: 服务端代码 import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.

  • C#实现多线程下载文件的方法

    本文实例讲述了C#实现多线程下载文件的方法.分享给大家供大家参考.具体实现方法如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Threading; using System.Net; namespace WfpApp { public class MultiDownload { #region 变量 pri

  • android实现多线程下载文件(支持暂停、取消、断点续传)

    多线程下载文件(支持暂停.取消.断点续传) 多线程同时下载文件即:在同一时间内通过多个线程对同一个请求地址发起多个请求,将需要下载的数据分割成多个部分,同时下载,每个线程只负责下载其中的一部分,最后将每一个线程下载的部分组装起来即可. 涉及的知识及问题 请求的数据如何分段 分段完成后如何下载和下载完成后如何组装到一起 暂停下载和继续下载的实现(wait().notifyAll().synchronized的使用) 取消下载和断点续传的实现 一.请求的数据如何分段 首先通过HttpURLConne

  • Android实现多线程下载图片的方法

    很多时候我们需要在Android设备上下载远程服务器上的图片进行显示,今天整理出两种比较好的方法来实现远程图片的下载. 方法一.直接通过Android提供的Http类访问远程服务器,这里AndroidHttpClient是SDK 2.2中新出的方法,API Level为8,大家需要注意下,静态访问可以直接调用,如果SDK版本较低可以考虑Apache的Http库,当然HttpURLConnection 或URLConnection也可以. static Bitmap downloadBitmapB

  • RxJava2.x+ReTrofit2.x多线程下载文件的示例代码

    写在前面: 接到公司需求:要做一个apk升级的功能,原理其实很简单,百度也一大堆例子,可大部分都是用框架,要么就是HttpURLConnection,实在是不想这么干.正好看了两天的RxJava2.x+ReTrofit2.x,据说这俩框架是目前最火的异步请求框架了.固本文使用RxJava2.x+ReTrofit2.x实现多线程下载文件的功能. 如果对RxJava2.x+ReTrofit2.x不太了解的请先去看相关的文档. 大神至此请无视. 思路分析: 思路及其简洁明了,主要分为以下四步 1.获取

  • Android版多线程下载 仿下载助手(最新)

    首先声明一点: 这里的多线程下载并不是指多个线程下载一个 文件,而是每个线程负责一个文件,今天给大家分享一个多线程下载的 例子.先看一下效果,点击下载开始下载,同时显示下载进度,下载完成,变成程安装,点击安装提示安装应用. 界面效果图: 线程池ThreadPoolExecutor ,先简单学习下这个线程池的使用 /** * Parameters: corePoolSize the number of threads to keep in the pool, even if they are id

  • Android应用读取Excel文件的方法

    本文实例讲述了Android应用读取Excel文件的方法.分享给大家供大家参考,具体如下: ReadExcel.java文件: public class ReadExcel extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState)

  • android编程之XML文件解析方法详解(附源码)

    本文实例讲述了android编程之XML文件解析方法.分享给大家供大家参考,具体如下: 在android开发中,经常用到去解析xml文件,常见的解析xml的方式有一下三种:SAX.Pull.Dom解析方式.最近做了一个android版的CSDN阅读器,用到了其中的两种(sax,pull),今天对android解析xml的这三种方式进行一次总结. 今天解析的xml示例(channels.xml)如下: <?xml version="1.0" encoding="utf-8

随机推荐