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

   2015-06-24 0
核心提示:这篇文章主要介绍了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程序设计有所帮助。

 
标签: Android 下载
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 说一说Android Studio和IDEA中一个很有用的内存调试插件
    说一说Android Studio和IDEA中一个很有用的内存
    JetBrains JVM Debugger Memory View plugin 在我最近的研发活动期间寻找新的工具,以提高我的开发经验,使Android Studio的生活更轻松,我发现一个有用的插件,我从来没有听说过。 这就是为什么,我决定写这个强大的工具,它如何帮助我与内存调试我的应用程
  • 安卓中通知功能的具体实现
    安卓中通知功能的具体实现
    通知[Notification]是Android中比较有特色的功能,当某个应用程序希望给用户发出一些提示信息,而该应用程序又不在前台运行时,就可以借助通知实现。使用通知的步骤1、需要一个NotificationManager来获得NotificationManager manager = (NotificationManager
    02-05 安卓开发
  • Android view系统分析-setContentView
    Android view系统分析-setContentView
    第一天上班,列了一下今年要学习的东西。主要就是深入学习Android相关的系统源代码,夯实基础。对于学习Android系统源代码,也没什么大概,就从我们平常使用最基础的东西学起,也就是从view这个切入点开始学习Android的源码,在没分析源码之前,我们有的时候
    02-05 安卓开发
  • 如何进行网络视频截图/获取视频的缩略图
    如何进行网络视频截图/获取视频的缩略图
    小编导读:获取视频的缩略图,截图正在播放的视频某一帧,是在音视频开发中,常遇到的问题。本文是主要用于点播中截图视频,同时还可以获取点播视频的缩略图进行显示,留下一个问题,如下图所示, 如果要获取直播中节目视频缩略图,该怎么做呢?(ps:直播是直
  • Android NDK 层发起 HTTP 请求的问题及解决
    Android NDK 层发起 HTTP 请求的问题及解决
    前言新的一年,大家新年快乐~~鸡年大吉!本次给大家带来何老师的最新文章~虽然何老师还在过节,但依然放心不下广大开发者,在此佳节还未结束之际,给大家带来最新的技术分享~ 事件的起因不说了,总之是需要实现一个 NDK 层的网络请求。为了多端适用,还是选择
  • SDK热更之如何在SDK代码中自动插桩及如何生成补
    写在前面本文是SDKHotfix相关的SDK热更系列文章中的一篇,以下为项目及系列文章相关链接:SDKHotfix整体介绍:http://blog.bihe0832.com/sdk_hotfix_project.htmlSDKHotfix对应github地址:https://github.com/bihe0832/SDKHoxFix这篇文章主要介绍一下SDK热更
  • 安装量破千万的第一个产品,我总结了3句话
    安装量破千万的第一个产品,我总结了3句话
    在今天的文章中,作者回顾了自己的第一个产品,他说“我做的第一款产品,是我的一块里程碑。”一起来看看~背景老牌大型互联网公司,部门内部创业的一个项目。我作为产品经理,也是第一次做产品经理,主导产品项目。实际上,项目初期包括我和安卓开发2个人。开
  • 移动周刊第 176 期:Android 知识梳理
    移动周刊第 176 期:Android 知识梳理
    写在前面 本期移动周刊第 176 期如约而至,聚焦 Android、iOS、VR/AR/MR、直播等前沿移动开发技术,收录一周最热点,解读开发技巧,每周三移动周刊抢先看,我们希望从中能够让你有一些收获,如果你有好的文章以及优化建议,请发送邮件至mobilehub@csdn.net,
  • Android插件化(六): OpenAtlasの改写aapt以防止资源ID冲突
    Android插件化(六): OpenAtlasの改写aapt以防
    引言Android应用程序的编译中,负责资源打包的是aapt,如果不对打包后的资源ID进行控制,就会导致插件中的资源ID冲突。所以,我们需要改写aapt的源码,以达到通过某种方式传递资源ID的Package ID,通过aapt打包时获取到这个Package ID并且应用才插件资源的命名
    02-05 安卓开发
  • Android架构(一)MVP架构在Android中的实践
    Android架构(一)MVP架构在Android中的实践
    为什么要重视程序的架构设计 对程序进行架构设计的原因,归根结底是为了 提高生产力 。通过设计是程序模块化,做到模块内部的 高聚合 和模块之间的 低耦合 (如依赖注入就是低耦合的集中体现)。 这样做的好处是使得程序开发过程中,开发人员主需要专注于一点,
    02-05 安卓开发
点击排行