Android 断点续传原理以及实现

Android 断点续传原理以及实现

0.  前言

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

1.  断点续传原理

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

2.  Activity的按钮响应

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

public class FileInfo implements Serializable{ private String url; //URL private int length; //长度或结束位置 private int start; //开始位置 private int now;//当前进度 //构造方法,set/get略 } //开始按钮逻辑,停止逻辑大致相同 strat.setOnClickListener(new View.OnClickListener() { @Override public 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将对象传递给Service mHandle.obtainMessage(0, fileInfo).sendToTarget(); } catch (Exception e) { e.printStackTrace(); } finally { //流的回收逻辑略 } } }

4.  数据库操作封装

在Service的handleMessage()方法中拿到有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; } @Override public 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); //把进度发送给Activity finished += 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告知服务器从哪里开始传递数据,传递到哪里结束,本地使用RandomAccessFile的seek()方法进行数据的本地存储。使用广播将进度的百分比传递给Activity,Activity再改变ProcessBar进行UI调整。

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

6.  效果如下所示

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

时间: 2024-11-02 14:18:43

Android 断点续传原理以及实现的相关文章

Android 断点续传原理以及实现_Android

Android 断点续传原理以及实现 0.  前言 在Android开发中,断点续传听起来挺容易,在下载一个文件时点击暂停任务暂停,点击开始会继续下载文件.但是真正实现起来知识点还是蛮多的,因此今天有时间实现了一下,并进行记录. 1.  断点续传原理 在本地下载过程中要使用数据库实时存储到底存储到文件的哪个位置了,这样点击开始继续传递时,才能通过HTTP的GET请求中的setRequestProperty()方法可以告诉服务器,数据从哪里开始,到哪里结束.同时在本地的文件写入时,RandomAc

Android 断点续传的原理剖析与实例讲解_Android

 本文所要讲的是Android断点续传的内容,以实例的形式进行了详细介绍.        一.断点续传的原理        其实断点续传的原理很简单,就是在http的请求上和一般的下载有所不同而已.        打个比方,浏览器请求服务器上的一个文时,所发出的请求如下:        假设服务器域名为www.jizhuomi.com/android,文件名为down.zip. get /down.zip http/1.1 accept: image/gif, image/x-xbitmap,

Android 断点续传的原理剖析与实例讲解

本文所要讲的是Android断点续传的内容,以实例的形式进行了详细介绍. 一.断点续传的原理 其实断点续传的原理很简单,就是在http的请求上和一般的下载有所不同而已. 打个比方,浏览器请求服务器上的一个文时,所发出的请求如下: 假设服务器域名为www.jizhuomi.com/android,文件名为down.zip. get /down.zip http/1.1 accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, appl

深度理解Android InstantRun原理以及源码分析

深度理解Android InstantRun原理以及源码分析 @Author 莫川 Instant Run官方介绍 简单介绍一下Instant Run,它是Android Studio2.0以后新增的一个运行机制,能够显著减少你第二次及以后的构建和部署时间.简单通俗的解释就是,当你在Android Studio中改了你的代码,Instant Run可以很快的让你看到你修改的效果.而在没有Instant Run之前,你的一个小小的修改,都肯能需要几十秒甚至更长的等待才能看到修改后的效果. 传统的代

android lbs-老师,您好:请教Android定位原理

问题描述 老师,您好:请教Android定位原理 我现在在做的是个Android定位系统,不能用第三方的定位API,像高德.百度等都不能用,我现在除了找到GPS定位能用之外,到目前还没找到其他的合适的定位方法,劳烦老师给我解答一下,谢谢您了! 解决方案 可以通过基站定位,你手机和基站有交互,通过对信号强弱得分析和基站得分布对应的位置,获取你所在得位置.

Android Handler 原理分析及实例代码

Android Handler 原理分析 Handler一个让无数android开发者头疼的东西,希望我今天这边文章能为您彻底根治这个问题 今天就为大家详细剖析下Handler的原理 Handler使用的原因 1.多线程更新Ui会导致UI界面错乱 2.如果加锁会导致性能下降 3.只在主线程去更新UI,轮询处理 Handler使用简介 其实关键方法就2个一个sendMessage,用来接收消息 另一个是handleMessage,用来处理接收到的消息 下面是我参考疯狂android讲义,写的一个子

Android GC原理探究

前言 想写一篇关于android GC的想法来源于追查一个魅族手机图片滑动卡顿问题,由于不断的GC导致的丢帧卡顿的问题让我们想了很多方案去解决,所以就打算详细的看看内存分配和GC的原理,为什么会不断的GC,GC ALLOC和GC COCURRENT有什么区别,能不能想办法扩大堆内存减少GC的频次等等. 1.JVM内存回收机制 1.1 回收算法 标记回收算法(Mark and Sweep GC) 从"GC Roots"集合开始,将内存整个遍历一次,保留所有可以被GC Roots直接或间接

Android Monkey原理探讨

0x0 概述 本文不涉及如何使用monkey,官网说得够详细了,网上资料也一大堆.本文着重探讨monkey的实现原理,以及基于这些原理,我们可以做些什么?本文涉及的Monkey的源码位于AOSP的development项目的cmds目录下. 0x1 Monkey事件触发原理 Monkey的主要作用是,发送一些随机交互事件模拟人的随机操作.它是如何触发各种事件的呢? 1.1 触摸事件 触摸事件包括屏幕以及物理键的触摸,滑动,点击事件.我们可以通过发送一些adb命令模拟这些事件.不过Monkey实现

Android 显示原理简介

转:http://djt.qq.com/article/view/987 作者:yearzhu,2011年进入腾讯公司,从事过Web端及移动端的测试工作,喜爱新鲜事物及新技术,目前在SNG开放平台测试组负责的移动互联SDK的测试工作.   现在越来越多的应用开始重视流畅度方面的测试,了解Android应用程序是如何在屏幕上显示的则是基础中的基础,就让我们一起看看小小屏幕中大大的学问.这也是我下篇文章--<Android应用流畅度测试分析>的基础.       首先,用一句话来概括一下Andro