iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >怎么在Android中利用多线程实现一个断点续传下载功能
  • 622
分享到

怎么在Android中利用多线程实现一个断点续传下载功能

android多线程roi 2023-05-31 10:05:54 622人浏览 泡泡鱼
摘要

怎么在Android中利用多线程实现一个断点续传下载功能?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。原理其实断点续传的原理很简单,从字面上理解,所谓断点续传就是从停止的地方重

怎么在Android中利用多线程实现一个断点续传下载功能?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

原理

其实断点续传的原理很简单,从字面上理解,所谓断点续传就是从停止的地方重新下载。
断点:线程停止的位置。
续传:从停止的位置重新下载。

用代码解析就是:
断点:当前线程已经下载完成的数据长度。
续传:向服务器请求上次线程停止位置之后的数据。

原理知道了,功能实现起来也简单。每当线程停止时就把已下载的数据长度写入记录文件,当重新下载时,从记录文件读取已经下载了的长度。而这个长度就是所需要的断点。

续传的实现也简单,可以通过设置网络请求参数,请求服务器从指定的位置开始读取数据。
而要实现这两个功能只需要使用到HttpURLconnection里面的setRequestProperty方法便可以实现.

public void setRequestProperty(String field, String newValue)

如下所示,便是向服务器请求500-1000之间的500个byte:

conn.setRequestProperty("Range", "bytes=" + 500 + "-" + 1000);

以上只是续传的一部分需求,当我们获取到下载数据时,还需要将数据写入文件,而普通发File对象并不提供从指定位置写入数据的功能,这个时候,就需要使用到RandoMaccessFile来实现从指定位置给文件写入数据的功能。

public void seek(long offset)

如下所示,便是从文件的的第100个byte后开始写入数据。

raFile.seek(100);

而开始写入数据时还需要用到RandomAccessFile里面的另外一个方法

public void write(byte[] buffer, int byteOffset, int byteCount)

该方法的使用和OutputStream的write的使用一模一样…

以上便是断点续传的原理。

多线程断点续传

而多线程断点续传便是在单线程的断点续传上延伸的,而多线程断点续传是把整个文件分割成几个部分,每个部分由一条线程执行下载,而每一条下载线程都要实现断点续传功能。
为了实现文件分割功能,我们需要使用到HttpURLconnection的另外一个方法:

public int getContentLength()

当请求成功时,可以通过该方法获取到文件的总长度。

每一条线程下载大小 = fileLength / THREAD_NUM

如下图所示,描述的便是多线程的下载模型:

怎么在Android中利用多线程实现一个断点续传下载功能

在多线程断点续传下载中,有一点需要特别注意:

由于文件是分成多个部分是被不同的线程的同时下载的,这就需要,每一条线程都分别需要有一个断点记录,和一个线程完成状态的记录;

如下图所示:

怎么在Android中利用多线程实现一个断点续传下载功能

只有所有线程的下载状态都处于完成状态时,才能表示文件已经下载完成。
实现记录的方法多种多样,我这里采用的是jdk自带的Properties类来记录下载参数。

断点续传结构

通过原理的了解,便可以很快的设计出断点续传工具类的基本结构图

怎么在Android中利用多线程实现一个断点续传下载功能

IDownloadListener.java

  package com.arialyy.frame.http.inf;  import java.net.HttpURLConnection;    public interface IDownloadListener {        public void onCancel();        public void onFail();        public void onPreDownload(HttpURLConnection connection);        public void onProgress(long currentLocation);        public void onChildComplete(long finishLocation);        public void onStart(long startLocation);        public void onChildResume(long resumeLocation);        public void onResume(long resumeLocation);        public void onStop(long stopLocation);        public void onComplete();  }

该类是下载监听接口

DownloadListener.java

import java.net.HttpURLConnection;public class DownloadListener implements IDownloadListener {  @Override  public void onResume(long resumeLocation) {  }  @Override  public void onCancel() {  }  @Override  public void onFail() {  }  @Override  public void onPreDownload(HttpURLConnection connection) {  }  @Override  public void onProgress(long currentLocation) {  }  @Override  public void onChildComplete(long finishLocation) {  }  @Override  public void onStart(long startLocation) {  }  @Override  public void onChildResume(long resumeLocation) {  }  @Override  public void onStop(long stopLocation) {  }  @Override  public void onComplete() {  }}

下载参数实体

   private class DownloadEntity {    //文件总长度    long fileSize;    //下载链接    String downloadUrl;    //线程Id    int threadId;    //起始下载位置    long startLocation;    //结束下载的文章    long endLocation;    //下载文件    File tempFile;    Context context;    public DownloadEntity(Context context, long fileSize, String downloadUrl, File file, int threadId, long startLocation, long endLocation) {      this.fileSize = fileSize;      this.downloadUrl = downloadUrl;      this.tempFile = file;      this.threadId = threadId;      this.startLocation = startLocation;      this.endLocation = endLocation;      this.context = context;    }  }

该类是下载信息配置类,每一条子线程的下载都需要一个下载实体来配置下载信息。

下载任务线程

    private class DownLoadTask implements Runnable {    private static final String TAG = "DownLoadTask";    private DownloadEntity dEntity;    private String configFPath;    public DownLoadTask(DownloadEntity downloadInfo) {      this.dEntity = downloadInfo;      configFPath = dEntity.context.getFilesDir().getPath() + "/temp/" + dEntity.tempFile.getName() + ".properties";    }    @Override    public void run() {      try {        L.d(TAG, "线程_" + dEntity.threadId + "_正在下载【" + "开始位置 : " + dEntity.startLocation + ",结束位置:" + dEntity.endLocation + "】");        URL url = new URL(dEntity.downloadUrl);        HttpURLConnection conn = (HttpURLConnection) url.openConnection();        //在头里面请求下载开始位置和结束位置        conn.setRequestProperty("Range", "bytes=" + dEntity.startLocation + "-" + dEntity.endLocation);        conn.setRequestMethod("GET");        conn.setRequestProperty("Charset", "UTF-8");        conn.setConnectTimeout(TIME_OUT);        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");        conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msWord, *  public void download(final Context context, @NonNull final String downloadUrl, @NonNull final String filePath,             @NonNull final DownloadListener downloadListener) {    isDownloading = true;    mCurrentLocation = 0;    isStop = false;    isCancel = false;    mCancelNum = 0;    mStopNum = 0;    final File dFile = new File(filePath);    //读取已完成的线程数    final File configFile = new File(context.getFilesDir().getPath() + "/temp/" + dFile.getName() + ".properties");    try {      if (!configFile.exists()) { //记录文件被删除,则重新下载        newTask = true;        FileUtil.createFile(configFile.getPath());      } else {        newTask = false;      }    } catch (Exception e) {      e.printStackTrace();      mListener.onFail();      return;    }    newTask = !dFile.exists();    new Thread(new Runnable() {      @Override      public void run() {        try {          mListener = downloadListener;          URL url = new URL(downloadUrl);          HttpURLConnection conn = (HttpURLConnection) url.openConnection();          conn.setRequestMethod("GET");          conn.setRequestProperty("Charset", "UTF-8");          conn.setConnectTimeout(TIME_OUT);          conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");          conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");          conn.connect();          int len = conn.getContentLength();          if (len < 0) { //网络被劫持时会出现这个问题            mListener.onFail();            return;          }          int code = conn.getResponseCode();          if (code == 200) {            int fileLength = conn.getContentLength();            //必须建一个文件            FileUtil.createFile(filePath);            RandomAccessFile file = new RandomAccessFile(filePath, "rwd");            //设置文件长度            file.setLength(fileLength);            mListener.onPreDownload(conn);            //分配每条线程的下载区间            Properties pro = null;            pro = Util.loadConfig(configFile);            int blockSize = fileLength / THREAD_NUM;            SparseArray<Thread> tasks = new SparseArray<>();            for (int i = 0; i < THREAD_NUM; i++) {              long startL = i * blockSize, endL = (i + 1) * blockSize;              Object state = pro.getProperty(dFile.getName() + "_state_" + i);              if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成                mCurrentLocation += endL - startL;                L.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");                mCompleteThreadNum++;                if (mCompleteThreadNum == THREAD_NUM) {                  if (configFile.exists()) {                    configFile.delete();                  }                  mListener.onComplete();                  isDownloading = false;                  System.GC();                  return;                }                continue;              }              //分配下载位置              Object record = pro.getProperty(dFile.getName() + "_record_" + i);              if (!newTask && record != null && Long.parseLong(record + "") > 0) {    //如果有记录,则恢复下载                Long r = Long.parseLong(record + "");                mCurrentLocation += r - startL;                L.d(TAG, "++++++++++ 线程_" + i + "_恢复下载 ++++++++++");                mListener.onChildResume(r);                startL = r;              }              if (i == (THREAD_NUM - 1)) {                endL = fileLength;//如果整个文件的大小不为线程个数的整数倍,则最后一个线程的结束位置即为文件的总长度              }              DownloadEntity entity = new DownloadEntity(context, fileLength, downloadUrl, dFile, i, startL, endL);              DownLoadTask task = new DownLoadTask(entity);              tasks.put(i, new Thread(task));            }            if (mCurrentLocation > 0) {              mListener.onResume(mCurrentLocation);            } else {              mListener.onStart(mCurrentLocation);            }            for (int i = 0, count = tasks.size(); i < count; i++) {              Thread task = tasks.get(i);              if (task != null) {                task.start();              }            }          } else {            FL.e(TAG, "下载失败,返回码:" + code);            isDownloading = false;            System.gc();            mListener.onFail();          }        } catch (IOException e) {          FL.e(this, "下载失败【downloadUrl:" + downloadUrl + "】\n【filePath:" + filePath + "】" + FL.getPrintException(e));          isDownloading = false;          mListener.onFail();        }      }    }).start();  }

其实也没啥好说的,注释已经很完整了,需要注意两点
1、恢复下载时:已下载的文件大小 = 该线程的上一次断点的位置 - 该线程起始下载位置;
2、为了保证下载文件的完整性,只要记录文件不存在就需要重新进行下载;

看完上述内容,你们掌握怎么在Android中利用多线程实现一个断点续传下载功能的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注编程网精选频道,感谢各位的阅读!

--结束END--

本文标题: 怎么在Android中利用多线程实现一个断点续传下载功能

本文链接: https://www.lsjlt.com/news/224690.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 怎么在Android中利用多线程实现一个断点续传下载功能
    怎么在Android中利用多线程实现一个断点续传下载功能?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。原理其实断点续传的原理很简单,从字面上理解,所谓断点续传就是从停止的地方重...
    99+
    2023-05-31
    android 多线程 roi
  • 怎么在Android中实现一个多线程断点续传下载功能
    本篇文章给大家分享的是有关怎么在Android中实现一个多线程断点续传下载功能,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1、布局实现具体布局内容如下:<LinearL...
    99+
    2023-05-30
    android
  • Android中怎么利用FTP实现多线程断点续传下载上传功能
    Android中怎么利用FTP实现多线程断点续传下载上传功能,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。FTP下载原理FTP单线程断点续传FTP和传统的HTT...
    99+
    2023-05-30
    android
  • 怎么在Android应用中实现一个网络多线程断点续传下载功能
    怎么在Android应用中实现一个网络多线程断点续传下载功能?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。原理多线程下载的原理就是将要下载的文件分成若干份,其中...
    99+
    2023-05-31
    android 断点续传 多线程
  • android怎么实现多线程断点续传功能
    这篇文章主要介绍了android怎么实现多线程断点续传功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。具体内容如下布局:<xml version="...
    99+
    2023-05-30
    android 多线程
  • android原生实现多线程断点续传功能
    本文实例为大家分享了android实现多线程断点续传功能的具体代码,供大家参考,具体内容如下 需求描述: 输入一个下载地址,和要启动的线程数量,点击下载 利用多线程将文件下载到手机端...
    99+
    2024-04-02
  • 怎么在Android中实现一个多线程下载功能
    怎么在Android中实现一个多线程下载功能?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。布局      &nb...
    99+
    2023-05-30
    android 多线程
  • Java实现多线程下载和断点续传
    java的多线程下载能够明显提升下载的速度,平时我们用的迅雷软件之所以能够下载那么快,就是使用了多线程;当用户在下载的过程中,有断电或断网的可能,当用户再次点击下载时,应该让用户接着...
    99+
    2024-04-02
  • 怎么在Android应用中实现一个HTTP多线程下载功能
    本篇文章为大家展示了怎么在Android应用中实现一个HTTP多线程下载功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。多线程断点需要的功能多线程下载,支持断点。使用多线程的好处:使用多线程下载会...
    99+
    2023-05-31
    android http 多线程
  • Android入门之利用OKHttp实现断点续传功能
    目录简介课程目标断点下载的原理自定义Android里的ProgressBar的样式项目结构前端代码后端代码DbOpeerateHelper.javaDBService.javaDow...
    99+
    2023-01-09
    Android OKHttp断点续传功能 Android OKHttp断点续传 Android 断点续传 Android OKHttp
  • Android应用中的断点下载功能怎么利用HttpURLConnection实现
    Android应用中的断点下载功能怎么利用HttpURLConnection实现?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。HttpCilent 跟 HttpURLConne...
    99+
    2023-05-31
    android httpurlconnection roi
  • 怎么在Android中利用DownloadManager实现一个文件下载功能
    本篇文章为大家展示了怎么在Android中利用DownloadManager实现一个文件下载功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Android中DownloadManager实现文件下...
    99+
    2023-05-31
    android downloadmanager age
  • 如何在Android应用中利用ADT实现一个离线下载功能
    今天就跟大家聊聊有关如何在Android应用中利用ADT实现一个离线下载功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Android ADT 离线下载操作步骤可以利用在线安装地址...
    99+
    2023-05-31
    android adt roi
  • Java中怎么实现断点续传功能
    这篇文章给大家介绍Java中怎么实现断点续传功能,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。(一)断点续传的原理   其实断点续传的原理很简单,就是在Http的请求上和一般的下载有所不同而已。   打个比方,浏览器请...
    99+
    2023-06-03
  • C#中怎么实现断点续传功能
    本篇文章为大家展示了C#中怎么实现断点续传功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。以下是一个请求报文与相应的回复报文的例子:GET /image/index_r4_c1.jpg&...
    99+
    2023-06-17
  • Android应用中的断点续传下载如何利用HTTP协议实现
    这期内容当中小编将会给大家带来有关Android应用中的断点续传下载如何利用HTTP协议实现,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。FileDownloader.java    ...
    99+
    2023-05-31
    android http roi
  • Android如何实现简单断点续传和下载到本地功能
    这篇文章主要介绍了Android如何实现简单断点续传和下载到本地功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。具体内容如下效果展示导入依赖与权限依赖compile&nbs...
    99+
    2023-05-30
    android
  • 怎么在JAVA中利用HttpURLConnection实现一个文件上传下载功能
    怎么在JAVA中利用HttpURLConnection实现一个文件上传下载功能?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。HttpURLConnection文...
    99+
    2023-05-31
    java httpurlconnection ava
  • 利用断点续传实现下载的原理是什么
    今天就跟大家聊聊有关利用断点续传实现下载的原理是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。HTTP断点续传报文要实现HTTP断点续传必须要简单了解以下几个报文。Accept-...
    99+
    2023-05-31
    断点续传
  • android中的多线程下载怎么利用AsyncTask实现
    android中的多线程下载怎么利用AsyncTask实现?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。01 效果图02 核心类 - DownloadTask.classp...
    99+
    2023-05-31
    android asynctask 多线程
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作