>>分享Android开发相关的技术 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 19896 个阅读者 刷新本主题
 * 贴子主题:  Android多线程断点续传 回复文章 点赞(0)  收藏  
作者:mary    发表时间:2020-03-31 20:49:58     消息  查看  搜索  好友  邮件  复制  引用

         在Android下面的断点续传和java下面没有太大的冲突,就是在配置文件里面加上一些特定的访问权限就可以了

         如下式在AndroidManifest.xml加入的权限
                   <!--    访问 internet 权限  -->

                  <uses-permission android:name="android.permission.INTERNET" />

                  <!--    在 SDCard 中创建与删除文件权限 -->

                  <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

                  <!--    往 SDCard 写入数据权限 -->

                  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

         这个准备工作做好了就可以直接编码了

         第一步创建multiThreaddownload.java

         package com.cn.download;

         import java.io.File;

         import java.io.FileInputStream;

         import java.io.InputStream;

         import java.io.RandomAccessFile;

         import java.net.URL;

         import java.net.URLConnection;

         import com.cn.coocaa.download.FileDownloadThread;

         public class MultiThreadDownload extends Thread {

                 //定义的一些常量变量,看名字就知道什么意思了

           private static final int BUFFER_SIZE = 1024;

           private int blockSize;

           private int threadNum = 5;

           private int fileSize;

           private int downloadedSize;

           String urlStr, threadNo, fileName;

           private String savePath;

           private int downloadPercent = 0 , downloadSpeed = 0, usedTime=0;

           private long startTime,curTime;

           private boolean completed = false;

                 //用URL,保存路径,保存名称来构造。

           public MultiThreadDownload(String URL, String savePath, String fileName) {

           this.urlStr = URL;

           this.savePath = savePath;

           this.fileName = fileName;

           }

                @Override

           public void run() {

           FileDownloadThread[] fds = new FileDownloadThread;

           try {

           URL url = new URL(urlStr);

           URLConnection conn = url.openConnection();

           fileSize = conn.getContentLength();

           blockSize = fileSize / threadNum;

           File file[] = new File;

                                                //根据默认的线程数,或者自己修改设置的线程数来分块,创建分块后的文件块

           for (int i = 0; i < threadNum; i++) {

           file[i] = new File(savePath + fileName + ".part"

           + String.valueOf(i));

                                                                 //将分块的文件交给每个线程处理,最后一块应该大于等于平均块,因为可能有余数

           FileDownloadThread fdt = new FileDownloadThread(url, file[i], i

           * blockSize, (i + 1) != threadNum ? ((i + 1)

           * blockSize - 1) : fileSize);

           fdt.setName("Thread" + i);

           fdt.start();

           fds[i] = fdt;

           }

           startTime = System.currentTimeMillis();

                                                //获取起始下载的时间,用次来计算速度。

           boolean finished = false;

           while (!finished) {

           downloadedSize = 0;

           finished = true;

           for (int i = 0; i < fds.length; i++) {

           downloadedSize += fds[i].getDownloadSize();

           if (!fds[i].isFinished()) {

           finished = false;

           }

           }

                                                                 //计算下载的百分比

           downloadPercent = (downloadedSize*100)/fileSize;

                                                                //获取当前时间,计算平均下载速度

           curTime = System.currentTimeMillis();

           usedTime =(int)((curTime-startTime)/1000);

           if(usedTime==0)

           usedTime =1;

           downloadSpeed = (downloadedSize/usedTime)/1024;

           sleep(1000);

           }

                                                //这个是分块下载完成的标志

           completed = true;

                                                //进行模块整合

           RandomAccessFile raf = new RandomAccessFile(savePath + fileName,

           "rw");

           byte[] tempbytes = new byte[BUFFER_SIZE];

           InputStream in = null;

           int byteread = 0;

           for (int i = 0; i < threadNum; i++) {

           in = new FileInputStream(file[i]);

           while ((byteread = in.read(tempbytes)) != -1)

           {

           raf.write(tempbytes, 0, byteread);

           }

                                                                //每次整合完一块就删除一块。

           in.close();

           file[i].delete();

           }

           raf.close();

                             } catch (Exception e) {

           // TODO: handle exception

           }

           }

                //获取下载百分比

           public int getDownloadPercent(){

           return this.downloadPercent;

           }

                //获取下载速度

           public int getDownloadSpeed(){

           return this.downloadSpeed;

           }

                //修改默认线程数

           public void setThreadNum(int threadNum){

           this.threadNum = threadNum;

           }

                 //分块下载完成的标志

           public boolean isCompleted(){

           return this.completed;

           }

         }

     第二步 创建filedownloadthread.java

package com.cn.download;

import java.io.BufferedInputStream;

import java.io.File;

import java.io.IOException;

import java.io.RandomAccessFile;

import java.net.URL;

import java.net.URLConnection;

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;

   }

             public void run() {

                     BufferedInputStream bis = null;

   RandomAccessFile fos = null;

   byte[] buf = new byte[BUFFER_SIZE];

   URLConnection con = null;

   try {

                                                //打开URL连接

   con = url.openConnection();

   con.setAllowUserInteraction(true);

                                               //判断是否该文件存在,如果存在且下载完成,直接返回。

   if ((file.length() + startPosition) == endPosition) {

   this.finished = true;

   }

                                               //文件未下载完成,获取到当前指针位置,继续下载。

                                              else {

   con.setRequestProperty("Range", "bytes="

   + (startPosition + file.length()) + "-" + endPosition);

   fos = new RandomAccessFile(file, "rw");

   fos.seek(file.length());

   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;

   }

   }

   this.finished = true;

   bis.close();

   fos.close();

   }

   } catch (IOException e) {

   System.out.println(getName() + " Error:" + e.getMessage());

   }

   }

             public boolean isFinished() {

   return finished;

   }

             public int getDownloadSize() {

   return downloadSize;

   }

}

上述两个文件就完成了多线程断点续传。

          无需使用任何配置文件或者数据库,就可以接上次的断点进行续传操作。

           原理流程:

          1、获取文件大小

          2、将文件按照所设定的线程数进行分块请求。

          3、检查是否存在断点情况,如果有断点情况则进行断点查找,然后再请求。

          4、分块下载。

          5、下载完成后文件整合,将分块文件删除掉。

          6、好了,你需要下载的文件就可以完成了。

            总之了,在这里也是一种实现无需配置文件的方式吧,我提供的只是一个外部调用包,所以这个配置文件或者数据库记录的东西有很大的局限性,所以就切割了,

           如果有什么更好的想法,希望能相互交流交流。

           转载请注明:http://alloxa.blog.51cto.com/

                                                  

----------------------------
原文链接:https://blog.51cto.com/alloxa/477043

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2020-04-08 09:09:22 重新编辑]
  Java面向对象编程-->输入与输出(上)
  JavaWeb开发-->JavaWeb应用入门(Ⅱ)
  JSP与Hibernate开发-->域对象在持久化层的四种状态
  Java网络编程-->通过JDBC API访问数据库
  精通Spring-->Vue简介
  Vue3开发-->Vue简介
  Android Gallery实现循环显示图像
  Android实用测试方法之Monkey与MonkeyRunner
  Android多屏幕适配
  编译Irrlicht On Android
  android 自动化测试之MonkeyRunner学习
  Android SDCard UnMounted 流程分析
  Android平台概述
  Android语音识别 android.speech 包分析
  Android OpenGL 学习笔记
  安卓隐藏标题栏方法
  Android Camera2.0 结合ImageReader拍照并解决图片偏转问题
  Android 架构
  安卓sqlite和Listview
  Android中NDK的含义和作用
  Android 判断当前设备是手机还是平板
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。