Android开发——断点续传原理以及实现

0.  前言

Android开发中,断点续传听起来挺容易,在下载一个文件时点击暂停任务暂停,点击开始会继续下载文件。但是真正实现起来知识点还是蛮多的,因此今天有时间实现了一下,并进行记录。本文原创,转载请注明出处为SEU_Calvin的博客。

 

1.  断点续传原理

在本地下载过程中要使用数据库实时存储到底存储到文件的哪个位置了,这样点击开始继续传递时,才能通过HTTPGET请求中的setRequestProperty()方法可以告诉服务器,数据从哪里开始,到哪里结束。同时在本地的文件写入时,RandomAccessFileseek()方法也支持在文件中的任意位置进行写入操作。同时通过广播将子线程的进度告诉ActivityProcessBar

 

2.  Activity的按钮响应

当点击开始按钮时,将url写在了FileInfo类的对象info中并通过IntentActivity传递到了Service中。这里使用setAction()来区分是开始按钮还是暂停按钮。

public class FileInfo implements Serializable{private String url; //URLprivate int length; //长度或结束位置private int start; //开始位置private int now;//当前进度
//构造方法,set/get略
}
//开始按钮逻辑,停止逻辑大致相同
strat.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Intent intent = new Intent(MainActivity.this,DownLoadService.class);intent.setAction(DownLoadService.ACTION_START);intent.putExtra("fileUrl",info);startService(intent);}
});

3.  Service中的子线程中获取文件大小

Service中的onStartCommand()中,将FileInfo对象从Intent中取出,如果是开始命令,则开启一个线程,根据该url去获得要下载文件的大小,将该大小写入对象并通过Handler传回Service,同时在本地创建一个相同大小的本地文件。暂停命令最后会讲到。

 public void run() {HttpURLConnection urlConnection = null;RandomAccessFile randomFile = null;try {URL url = new URL(fileInfo.getUrl());urlConnection = (HttpURLConnection) url.openConnection();urlConnection.setConnectTimeout(3000);urlConnection.setRequestMethod("GET");int length = -1;if (urlConnection.getResponseCode() == HttpStatus.SC_OK) {//获得文件长度length = urlConnection.getContentLength();}if (length <= 0) {return;}//创建相同大小的本地文件File dir = new File(DOWNLOAD_PATH);if (!dir.exists()) {dir.mkdir();}File file = new File(dir, FILE_NAME);randomFile = new RandomAccessFile(file, "rwd");randomFile.setLength(length);//长度给fileInfo对象fileInfo.setLength(length);//通过Handler将对象传递给ServicemHandle.obtainMessage(0, fileInfo).sendToTarget();} catch (Exception e) {e.printStackTrace();} finally {  //流的回收逻辑略}}}

4.  数据库操作封装

ServicehandleMessage()方法中拿到有length属性的FileInfo对象,并使用自定义的DownLoadUtil类进行具体的文件下载逻辑。这里传入上下文,因为数据库处理操作需要用到。

downLoadUtil = new DownLoadUtil(DownLoadService.this,info);
downLoadUtil.download();

这里有一个数据库操作的接口ThreadDAO,内部有增删改查等逻辑,用于记录下载任务的信息。自定义一个ThreadDAOImpl类将这里的逻辑实现,内部数据库创建关于继承SQLiteOpenHelper的自定义类的逻辑就不贴了,比较简单,该类会在ThreadDAOImpl类的构造方法中创建实例。完成底层数据库操作的封装

public interface ThreadDAO {//插入一条数据public void insert(FileInfo info);//根据URL删除一条数据public void delete(String url);//根据URL更新一条进度public void update(String url,int finished);//根据URL找到一条数据public List<FileInfo> get(String url);//是否存在public boolean isExits(String url);
}

5.  具体的文件下载逻辑

public class DownLoadUtil {//构造方法略public void download(){List<FileInfo> lists = threadDAO.get(fileInfo.getUrl());FileInfo info = null;if(lists.size() == 0){//第一次下载,创建子线程下载new MyThread(fileInfo).start();}else{//中间开始的info = lists.get(0);new MyThread(info).start();}}class MyThread extends Thread{private FileInfo info = null;public MyThread(FileInfo threadInfo) {this.info = threadInfo;}@Overridepublic void run() {//向数据库添加线程信息if(!threadDAO.isExits(info.getUrl())){threadDAO.insert(info);}HttpURLConnection urlConnection = null;RandomAccessFile randomFile =null;InputStream inputStream = null;try {URL url = new URL(info.getUrl());urlConnection = (HttpURLConnection) url.openConnection();urlConnection.setConnectTimeout(3000);urlConnection.setRequestMethod("GET");//设置下载位置int start = info.getStart() + info.getNow();urlConnection.setRequestProperty("Range","bytes=" + start + "-" + info.getLength());//设置文件写入位置File file = new File(DOWNLOAD_PATH,FILE_NAME);randomFile = new RandomAccessFile(file, "rwd");randomFile.seek(start);//向Activity发广播Intent intent = new Intent(ACTION_UPDATE);finished += info.getNow();if (urlConnection.getResponseCode() == HttpStatus.SC_PARTIAL_CONTENT) {//获得文件流inputStream = urlConnection.getInputStream();byte[] buffer = new byte[512];int len = -1;long time = System.currentTimeMillis();while ((len = inputStream.read(buffer))!= -1){//写入文件randomFile.write(buffer,0,len);//把进度发送给Activityfinished += len;//看时间间隔,时间间隔大于500ms再发if(System.currentTimeMillis() - time >500){time = System.currentTimeMillis();intent.putExtra("now",finished *100 /fileInfo.getLength());context.sendBroadcast(intent);}//判断是否是暂停状态if(isPause){threadDAO.update(info.getUrl(),finished);return; //结束循环}}//删除线程信息threadDAO.delete(info.getUrl());}}catch (Exception e){e.printStackTrace();}finally {//回收工作略}}}
}

上面也讲到使用自定义的DownLoadUtil类进行具体的文件下载逻辑,这也是最关键的部分了,在该类的构造方法中进行ThreadDAOImpl实例的创建。并在download()中通过数据库查询的操作,判断是否是第一次开始下载任务,如果是,则开启一个子线程MyThread进行下载任务,否则将进度信息从数据库中取出,并将该信息传递给MyThread

MyThread中,通过info.getStart() + info.getNow()设置开始下载的位置,如果是第一次下载两个数将都是0,如果是暂停后再下载,则info.getNow()会取出非0值,该值来自数据库存储。使用setRequestProperty告知服务器从哪里开始传递数据,传递到哪里结束,本地使用RandomAccessFileseek()方法进行数据的本地存储。使用广播将进度的百分比传递给ActivityActivity再改变ProcessBar进行UI调整。

这里很关键的一点是在用户点击暂停后会在Service中调用downLoadUtil.isPause = true,因此上面while循环会结束,停止下载并通过数据库的update()保存进度值。从而在续传时取出该值,重新对服务器发起文件起始点的下载任务请求,同时也在本地文件的相应位置继续写入操作。本文原创,转载请注明出处为SEU_Calvin的博客

最后补充一点,(17/4/11被面试问到了)关于断线续传的HTTP状态码并不是200,而是206,即HttpStatus.SC_PARTIAL_CONTENT。

6.  效果如下所示

Demo源码地址:链接: https://pan.baidu.com/s/1BYLtrt_rxuHFovuhirOw6g  密码: e25p

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/39111.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何实现断点续传

断点续传是指在网络传输中&#xff0c;当传输过程中出现异常或者用户主动停止传输时&#xff0c;能够恢复传输过程&#xff0c;避免重新传输已经传输过的数据&#xff0c;提高传输效率。实现断点续传可以通过以下方式&#xff1a; HTTP协议支持的断点续传 在HTTP协议中&#xf…

【MQ学习笔记】RocketMQ知识分析与总结

RocketMQ 为什么使用mq&#xff1f;mq的作用&#xff1f;mq对你项目带来了什么&#xff1f;不选mq行不行&#xff1f; 异步&#xff0c;MQ能够以异步的方式对消息进行处理&#xff0c;能够大大提高了系统的响应以及吞吐量解耦&#xff0c;MQ双方只需要负责生产或消费信息即可…

销售数据分析方法、如何写好一个专题分析报告、Hive大数据知识体系教程、大数据分析平台总体架构方案……| 本周精华...

▲点击上方卡片关注我&#xff0c;回复“8”&#xff0c;加入数据分析领地&#xff0c;一起学习数据分析&#xff0c;持续更新数据分析学习路径相关资料~&#xff08;精彩数据观点、学习资料、数据课程分享、读书会、分享会等你一起来乘风破浪~&#xff09;回复“小飞象”&…

老杨刷完了23个跨年演讲,这6场最适合网工

晚上好&#xff0c;我是老杨。 放假放了一阵子&#xff0c;老杨闲着没事儿&#xff0c;一共刷了23个跨年演讲。 好的演讲&#xff0c;和一本好书一样&#xff0c;都是可以震荡灵魂的。 也知道最近大家都忙得很&#xff0c;这里推荐7个最值得一听的跨年演讲&#xff0c;贴心吧…

朱广权李佳琦直播掉线,1.2 亿人在线等

作者 | 胡巍巍 出品 | 程序人生&#xff08;ID&#xff1a;coder_life&#xff09; 原来央视爸爸也有掉线的时候。 4月6日晚间&#xff0c;“国民段子手”朱广权连麦李佳琦&#xff0c;给湖北做公益带货直播。 “小朱配琦”的神仙组合&#xff0c;让人大呼过瘾&#xff0c;该直…

“我让 AI 来处理我 24 小时的音频信息——这会是未来吗?”

整理 | 郑丽媛 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 这几年 AI 发展和进化的速度&#xff0c;几乎可以用三个字来形容&#xff1a;杀疯了。 AI 下棋、AI 编程、AI 作画、AI 写小说、AI 预测蛋白质结构……当 AI 逐渐融入我们的生活&#xff0c;你是否设…

抗住百万人直播、被联合国推荐,起底飞书技术演进之路!

你去公司上班了吗&#xff1f; 随着近期接连不断传来的好消息&#xff0c;上班族开始关心起这问题来。但许多企业在相关政策的号召下&#xff0c;仍采取远程办公的方式。据艾媒咨询的数据显示&#xff0c;今年春节期间中国远程办公企业规模超过 1800 万家&#xff0c;远程办公人…

听8位淘宝工程师聊聊他们眼中的元宇宙 | 1024特辑

我们是技术工作者&#xff0c;致力于思考和创新&#xff0c;用代码去解决生活中的问题&#xff0c;为消费者的快乐和幸福而努力。 今天是1024程序员节&#xff0c;我们邀请了8位不同岗位的淘宝工程师&#xff0c;聊了聊他们眼中的未来消费生活&#xff0c;他们眼中的元宇宙&…

数字人的新革命,BAT的“冲高”战场

配图来自Canva可画 ChatGPT横空出世&#xff0c;让人们看到了数字人的另一种可能&#xff0c;将ChatGPT与虚拟数字人融合&#xff0c;研发出更加智能化、拟人化的虚拟数字人成为数字人厂商的新命题、新方向。 2月份&#xff0c;岭南股份、风语筑、开普云等10多家公司&#xf…

数字化直播沟通

目录 前言 一、介绍数字化&#xff08;5-10分钟&#xff09; 主播提问&#xff08;王&#xff09;&#xff1a; 回答&#xff08;向&#xff09;&#xff1a; 什么是数字化&#xff1f; 好的&#xff0c;我们来看下一个问题&#xff1a;什么是数字化转型&#xff1f; 好的…

部署React项目到云服务器(步骤清晰)

部署React项目到云服务器 前言(下载相关软件)开始部署服务器以及域名购买实例远程连接 或 XShell 7 远程连接服务器XShell 7 连接云服务器操作使用FileZilla将 打包后的 build(可能你们那里打包是dist)文件塞到服务器文件夹感谢看到这里&#xff01;点个关注再走啊&#xff01;…

云服务安装配置git

搭建网站&#xff0c;我们有时候是直接从github拉取代码&#xff0c;这就要配置git。 云服务器搭建网站还需要一些其他的基础配置&#xff0c;前面我们已经讲到&#xff0c;未进行配置的可以参考之前的文章。 云服务基本配置&#xff1a;腾讯云服务器小白保姆级教程_大鹏bmfm…

【回答问题】ChatGPT上线了!写出coco数据集的图像分类训练和预测函数代码?

写出coco数据集的图像分类训练代码 好的,我会尽力写出图像分类训练代码。首先,你需要准备好 COCO 数据集的图像和标签,并将其转换成适合你模型使用的格式。其次,你需要选择一个图像分类模型,并定义好模型的结构。接下来,你可以使用 PyTorch 等深度学习框架来实现训练代码…

服务器访问次数限制实现的思路

有个每分钟只能访问10次接口的需求&#xff0c;想到2个实现方法分享给大家&#xff0c;希望可以一起进步&#xff0c;一开始的思路是记录下用户访问的时间和次数&#xff0c;然后在写一些方法实现。最先想到是记录在数据库里&#xff0c;刚好数据库有记录访问日志的表&#xff…

若登陆账号错误次数过多则限制登陆一定时长(自定义时长)

前提须知:登陆拦截器此演示:登陆5次错误 则限制登陆时长5秒 业务层实现方法 在控制器中使用此方法,若判断用户账户和密码是否正确则返回用户对象定义session中的key为’count’定义一个日期对象存放时间,时间是当前时间的后5秒,将此时间存放进session中key为’time’中若登陆…

根据IP限制指定时间内访问接口的次数

在网上看见有人问一个问题&#xff1a;想限制一下某个接口在一分钟之内只能被同一个ip请求指定次数。 方法比较多&#xff0c;这里就用Redis做一个简单的限制。 大致逻辑&#xff1a; 把请求的ip作为key,请求次数作为value存储在Redis里面&#xff0c;第一次请求value为1&am…

openAI--十拳剑助你做AI时代的弄潮儿

AI它厉害&#xff08;diao&#xff09;吗&#xff1f; 最近大家玩chatgpt还好吗&#xff1f; 有被它的恋爱情商暴击到吗&#xff1f; 有没有觉得那在leetcode上所向无敌的技巧都是浮云吗&#xff1f; 今天&#xff0c;我为大家带来十个很好的AI平台。这一篇先介绍一下&…

虚拟数字人和GPT-4的结合,能否迎来新爆发?

最近&#xff0c;ChatGPT一直在互联网上狂飙&#xff0c;从 去年11月底推出到月活过亿&#xff0c;仅花了2个月的 时间。它既可以拥有美国的医学牌照、参加司法考试&#xff0c;又能写小说、编代码、查资料&#xff0c;还可 以陪你闲聊&#xff0c;你问它什么话题&#xff0c;它…

在一个领域里面发光、发热

大家好&#xff0c;这期分享一些好的公众号给家&#xff0c;希望对你以后成长路有所帮助&#xff0c;据我了解&#xff0c;公众号的作者都是在自己的领域里很努力&#xff0c;发光、发热&#xff0c;大家喜欢的都可以关注一下&#xff0c;支持一下&#xff0c;在此感谢大家的认…

低代码平台助力AIGC:让人工智能技术更加普及和高效

今年人工智能的风是吹了一波又一波&#xff0c;从ChatGPT到文心一言&#xff0c;短短四个多月的时间&#xff0c;GPT完成了从3.0、3.5到4.0的推新发布&#xff0c;一步步刷新了民众对于目前人工智能技术发展的认知底线&#xff0c;让人们直观地感受到了人工智能技术的蓬勃发展。…