Android实现多线程断点下载的方法

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

package cn.itcast.download;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import cn.itcast.mutiledownload.StreamTool;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
public class MutiledownloadActivity extends Activity implements OnClickListener {
  private ProgressBar pb;
  private Button bt;
  private TextView tv;
  private EditText et;
  boolean flag = true;
  boolean stopflag = false;
  private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      pb.setProgress(total);
      int max = pb.getMax();
      if (total >= (max - 1)) {
        total = max;
        flag = false;
      }
      int result = total * 100 / max;
      tv.setText("当前进度 :" + result + "%");
      super.handleMessage(msg);
    }
  };
  int total = 0;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    pb = (ProgressBar) this.findViewById(R.id.pb);
    bt = (Button) this.findViewById(R.id.bt);
    tv = (TextView) this.findViewById(R.id.tv_process);
    et = (EditText) this.findViewById(R.id.et);
    bt.setOnClickListener(this);
  }
  @Override
  public void onClick(View v) {
    switch (v.getId()) {
    case R.id.bt:
      // 创建一个子线程 定期的更新ui
      if("开始下载".equals(bt.getText().toString())){
        bt.setText("暂停");
        stopflag = false; //开始下载
      }
      else {
        bt.setText("开始下载");
        stopflag = true;
      }
        new Thread() {
          @Override
          public void run() {
            super.run();
            while (flag) {
              try {
                sleep(1000);
                // 如果total > = 文件长度
                Message msg = new Message();
                handler.sendMessage(msg);
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
          }
        }.start(); 

        // 开始执行下载的操作
        String path = et.getText().toString().trim();
        if ("".equals(path)) {
          Toast.makeText(this, "路径不能为空", 1).show();
          return;
        }
        try {
          URL url = new URL(path);
          HttpURLConnection conn = (HttpURLConnection) url
              .openConnection();
          conn.setRequestMethod("GET");
          conn.setConnectTimeout(5000);
          conn.setRequestProperty("User-Agent",
              "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
          int code = conn.getResponseCode();
          if (code == 200) {
            int len = conn.getContentLength();
            RandomAccessFile file = new RandomAccessFile(
                "/mnt/sdcard/" + getFilenName(path), "rwd");
            // 1.设置本地文件大小跟服务器的文件大小一致
            file.setLength(len);
            // 设置进度条的最大值
            pb.setMax(len);
            // 2 .假设开启3 个线程
            int threadnumber = 3;
            int blocksize = len / threadnumber;
            /**
             * 线程1 0~ blocksize 线程2 1*bolocksize ~ 2*blocksize 线程3
             * 2*blocksize ~ 文件末尾
             */
            for (int i = 0; i < threadnumber; i++) {
              int startposition = i * blocksize;
              int endpositon = (i + 1) * blocksize;
              if (i == (threadnumber - 1)) {
                // 最后一个线程
                endpositon = len;
              }
              DownLoadTask task = new DownLoadTask(i, path,
                  startposition, endpositon);
              task.start();
            }
          }
        } catch (Exception e) {
          Toast.makeText(this, "下载出现异常", 0).show();
          e.printStackTrace();
        }
      break;
    }
  }
  class DownLoadTask extends Thread {
    int threadid;
    String filepath;
    int startposition;
    int endpositon;
    public DownLoadTask(int threadid, String filepath, int startposition,
        int endpositon) {
      this.threadid = threadid;
      this.filepath = filepath;
      this.startposition = startposition;
      this.endpositon = endpositon;
    }
    @Override
    public void run() {
      try {
        File postionfile = new File("/mnt/sdcard/" + threadid + ".txt");
        URL url = new URL(filepath);
        HttpURLConnection conn = (HttpURLConnection) url
            .openConnection();
        System.out.println("线程" + threadid + "正在下载 " + "开始位置 : "
            + startposition + "结束位置 " + endpositon);
        if (postionfile.exists()) {
          FileInputStream fis = new FileInputStream(postionfile);
          byte[] result = StreamTool.getBytes(fis);
          String str = new String(result);
          if (!"".equals(str)) {
            int newstartposition = Integer.parseInt(str);
            if (newstartposition > startposition) {
              startposition = newstartposition;
            }
          }
        }
        // "Range", "bytes=2097152-4194303")
        conn.setRequestProperty("Range", "bytes=" + startposition + "-"
            + endpositon);
        conn.setRequestMethod("GET");
        conn.setConnectTimeout(5000);
        conn.setRequestProperty("User-Agent",
            "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
        InputStream is = conn.getInputStream();
        RandomAccessFile file = new RandomAccessFile("/mnt/sdcard/"
            + getFilenName(filepath), "rwd");
        // 设置 数据从文件哪个位置开始写
        file.seek(startposition);
        byte[] buffer = new byte[1024];
        int len = 0;
        // 代表当前读到的服务器数据的位置 ,同时这个值已经存储的文件的位置
        int currentPostion = startposition;
        // 创建一个文件对象 ,记录当前某个文件的下载位置
        while ((len = is.read(buffer)) != -1) {
          if (stopflag) {
            return;
          }
          file.write(buffer, 0, len);
          synchronized (MutiledownloadActivity.this) {
            total += len;
          }
          currentPostion += len;
          // 需要把currentPostion 信息给持久化到存储设备
          String position = currentPostion + "";
          FileOutputStream fos = new FileOutputStream(postionfile);
          fos.write(position.getBytes());
          fos.flush();
          fos.close();
        }
        file.close();
        System.out.println("线程" + threadid + "下载完毕");
        // 当线程下载完毕后 把文件删除掉
        if (postionfile.exists()) {
          postionfile.delete();
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
      super.run();
    }
  }
  public String getFilenName(String path) {
    int start = path.lastIndexOf("/") + 1;
    return path.substring(start, path.length());
  }
}

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

时间: 2015-05-28

详解Android中的多线程断点下载

首先来看一下多线程下载的原理.多线程下载就是将同一个网络上的原始文件根据线程个数分成均等份,然后每个单独的线程下载对应的一部分,然后再将下载好的文件按照原始文件的顺序"拼接"起来就构 成了完整的文件了.这样就大大提高了文件的下载效率.对于文件下载来说,多线程下载是必须要考虑的环节. 多线程下载大致可分为以下几个步骤: 一.获取服务器上的目标文件的大小 显然这一步是需要先访问一下网络,只需要获取到目标文件的总大小即可.目的是为了计算每个线程应该分配的下载任务. 二. 在本地创建一个跟原始

Android原生实现多线程断点下载实例代码

各位父老乡亲,我单汉三又回来了,今天为大家带来一个用原生的安卓写的多线程断点下载Demo. 通过本文你可以学习到: SQLite的基本使用,数据库的增删改查. Handler的消息处理与更新UI. Service(主要用于下载)的进阶与使用. 原生的json文件解析(多层嵌套). RandomAccessFile的基本使用,可以将文件分段. 基于HttpURLConnection的大文件下载. 上面内容结合,实现多线程,断点下载. Demo是在TV上运行的,图片显示的问题不要纠结了. 文件下载的

Android入门:多线程断点下载详细介绍

本案例在于实现文件的多线程断点下载,即文件在下载一部分中断后,可继续接着已有进度下载,并通过进度条显示进度.也就是说在文件开始下载的同时,自动创建每个线程的下载进度的本地文件,下载中断后,重新进入应用点击下载,程序检查有没有本地文件的存在,若存在,获取本地文件中的下载进度,继续进行下载.当下载完成后,自动删除本地文件. 一.多线程断点下载介绍 所谓的多线程断点下载就是利用多线程下载,并且可被中断,如果突然没电了,重启手机后可以继续下载,而不需要重新下载: 利用的技术有:SQLite存储各个线程的

android多线程断点下载-带进度条和百分比进度显示效果

android多线程断点下载,带进度条和百分比显示,断点下载的临时数据保存到SD卡的文本文档中,建议可以保存到本地数据库中,这样可以提高存取效率,从而提高系统性能. 效果: 打开软件: 下载中: 下载完毕: 附代码如下: package com.yy.multiDownloadOfBreakPoint; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.R

Android编程开发实现带进度条和百分比的多线程下载

本文实例讲述了Android编程开发实现带进度条和百分比的多线程下载.分享给大家供大家参考,具体如下: 继上一篇<java多线程下载实例详解>之后,可以将它移植到我们的安卓中来,下面是具体实现源码: DownActivity.java: package com.example.downloads; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.net.H

iOS开发网络篇—实现大文件的多线程断点下载

说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时开启多条线程下载一个较大的文件.因为实现过程较为复杂,所以下面贴出完整的代码. 实现思路:下载开始,创建一个和要下载的文件大小相同的文件(如果要下载的文件为100M,那么就在沙盒中创建一个100M的文件,然后计算每一段的下载量,开启多条线程下载各段的数据,分别写入对应的文件部分). 项目中用到的主要类如下: 完成的实现代码如下: 主控制器中的代码: #import "YYViewController.h" #import

Android自定义水平进度条的圆角进度

平时项目中经常用到自定义进度条样式,我们一般实现的也是下面的第一种,至于第二种的圆角进度,网上介绍的资料也不是很多,这里一起展示一下这两种的实现. 下面开始看代码,先从主界面布局开始看起: <ProgressBar style="@android:style/Widget.ProgressBar.Horizontal" android:layout_width="match_parent" android:layout_height="20dp&qu

Android ProgressBar进度条和ProgressDialog进度框的展示DEMO

在做手机开发时,经常碰到一些比较耗时的操作,这个时候进度条就开始派上用场了.这个demo展示了ProgressBar进度条和ProgressDialog进度框.一.ProgressDialog进度框,效果如图所示:代码如下: 复制代码 代码如下: //进度对话框按钮监听     class ProssButtonListener implements OnClickListener {         @Override         public void onClick(View v) {

Java实现多线程断点下载

JAVA多线程断点下载原理如图: 代码如下: import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.n

JS中实现一个下载进度条及播放进度条的代码

术上没太大难度,有难度的地方是怎么让整个动画比较流畅.一个主要问题是动画的滞后性:当下载进度到某个点的时候,你再用250ms的动画过渡过去,这个时候已经慢了,所以很多人可能因为这个原因或者嫌麻烦,直接就不做动画了,在进度事件触发的时候直接更新进度条相应的位置,不过我们可以尝试实现一下. 最后做出来的效果如下图所示: 小狗奔跑的动画是一个lottie动画,来自 codepen . 1. 获取下载进度 ajax里面可以拿到下载进度,如下代码所示: let xhr = new XMLHttpReque