即拿即用-Android单线程断点下载
之前有看过一个著名的断点下载的框架MultiThreadDownload,用的是线程池开启下载任务,点击暂停的时候将断点的信息保存在数据库里面,下次拿出来继续下载,本文的思路也和这个差不多。
这篇文章的代码将会在上次写的《即拿即用-HttpURLConnection分别实现图片,文本,文件的请求》的GitHub项目里面继续更新。完整下载地址在文章最后
该例子在下载中多次点击开始和暂停对进度进行控制,下面放上一张效果图:
主要步骤如下:
点击开始的时候,我们要先开一个网络连接去获取文件的长度:
/*** 点击开始*/public void onStartClick(View view) {// 开启fileName.setText(getfileName(urlstr));// 获得Activity传来的参数Log.i("test", "START" + fileInfo.toString());//开启一个下载任务new InitThread(fileInfo).start();}
/*** 开启一个网络连接用来获得下载文件的信息*/class InitThread extends Thread {private FileInfo mFileInfo = null;public InitThread(FileInfo mFileInfo) {super();this.mFileInfo = mFileInfo;}@Overridepublic void run() {HttpURLConnection conn = null;RandomAccessFile raf = null;try {URL url = new URL(mFileInfo.getUrl());conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5 * 1000);conn.setRequestMethod("GET");int code = conn.getResponseCode();int length = -1;if (code == HttpURLConnection.HTTP_OK) {length = conn.getContentLength();}//如果文件长度为小于0,表示获取文件失败,直接返回if (length <= 0) {return;}// 判断文件路径是否存在,不存在这创建File dir = new File(DownloadPath);if (!dir.exists()) {dir.mkdir();}// 创建本地文件File file = new File(dir, mFileInfo.getFileName());raf = new RandomAccessFile(file, "rwd");raf.setLength(length);// 设置文件长度mFileInfo.setLength(length);// 将ileInfo对象传送给HandlerMessage msg = Message.obtain();msg.obj = mFileInfo;msg.what = MSG_INIT;mHandler.sendMessage(msg);
// msg.setTarget(mHandler);} catch (Exception e) {e.printStackTrace();} finally {if (conn != null) {conn.disconnect();}try {if (raf != null) {raf.close();}} catch (IOException e) {e.printStackTrace();}}super.run();}}
获取文件的长度之后,发送一个handler消息通知应用去开启另外一个网络连接DownloadTask,进行下载:
// 从InitThread线程中获取FileInfo信息,然后开始下载任务Handler mHandler = new Handler() {public void handleMessage(android.os.Message msg) {switch (msg.what) {case MSG_INIT:FileInfo fileInfo = (FileInfo) msg.obj;Log.i("test", "INIT:" + fileInfo.toString());// 获取FileInfo對象,开始下载任务mTask = new DownloadTask(SingleThreadDownloadActivity.this, fileInfo);mTask.download();break;}}};
在开启下载任务之前,根据下载的地址作为条件,看一下数据库这个地址有没有上一次下载的信息,也就是上一次文件下载的长度,结束的位置等信息,有的话获取并传给下载任务,没有的话会在下载任务里面插入一条到数据库
/*** 查询数据库上一次下载的信息,有则获取,没有则新建*/public void download() {// 从数据库中获取到下载的信息List<ThreadInfo> list = mDao.queryThreads(mFileInfo.getUrl());ThreadInfo info = null;if (list.size() == 0) {info = new ThreadInfo(0, mFileInfo.getUrl(), 0, mFileInfo.getLength(), 0);} else {info = list.get(0);}//开启下载任务new DownloadThread(info).start();}
到了最关键的时候了,开启一个下载任务。一边下载一边记录下载的长度,并更新到数据库。如果点击了暂停,则跳出循环结束下载。
class DownloadThread extends Thread {private ThreadInfo threadInfo = null;public DownloadThread(ThreadInfo threadInfo) {this.threadInfo = threadInfo;}@Overridepublic void run() {Log.i("test", "开启一个下载任务");// 如果数据库不存在下载信息,添加下载信息if (!mDao.isExists(threadInfo.getUrl(), threadInfo.getId())) {mDao.insertThread(threadInfo);}HttpURLConnection conn = null;RandomAccessFile raf = null;InputStream is = null;try {URL url = new URL(mFileInfo.getUrl());conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5 * 1000);conn.setRequestMethod("GET");//开始位置为getFinished()开始上次结束的位置Log.i("test", "文件的长度"+mFileInfo.getLength()+" 上次结束的位置:" + threadInfo.getFinished());int start = threadInfo.getStart() + threadInfo.getFinished();// 设置下载文件开始到结束的位置(结束的位置也就是文件的长度)conn.setRequestProperty("Range", "bytes=" + start + "-" + threadInfo.getEnd());File file = new File(SingleThreadDownloadActivity.DownloadPath, mFileInfo.getFileName());raf = new RandomAccessFile(file, "rwd");raf.seek(start);mFinished += threadInfo.getFinished();int code = conn.getResponseCode();if (code == HttpURLConnection.HTTP_PARTIAL) {is = conn.getInputStream();byte[] bt = new byte[1024];int len = -1;// 定义UI刷新时间long time = System.currentTimeMillis();while ((len = is.read(bt)) != -1) {raf.write(bt, 0, len);//记录结束的位置mFinished += len;// 设置为500毫米更新一次if (System.currentTimeMillis() - time > 500) {time = System.currentTimeMillis();//发送一个广播提示下载的进度Intent intent = new Intent(SingleThreadDownloadActivity.ACTION_UPDATE);//结束的位置/文件长度*100=下载进度百分比intent.putExtra("finished", mFinished * 100 / mFileInfo.getLength());Log.i("test", mFinished * 100 / mFileInfo.getLength() + "");// 发送广播给ActivitymComtext.sendBroadcast(intent);}if (mIsPause) {//如果状态为暂停,则跳出循环,并记录这次结束的位置的长度mDao.updateThread(threadInfo.getUrl(), threadInfo.getId(), mFinished);return;}}}// 下载完成后,刪除数据库信息mDao.deleteThread(threadInfo.getUrl(), threadInfo.getId());Intent intent = new Intent(SingleThreadDownloadActivity.ACTION_UPDATE);//结束的位置/文件长度*100=下载进度百分比intent.putExtra("finished", 100);// 发送广播给ActivitymComtext.sendBroadcast(intent);Log.i("DownloadTask", "下载完毕");} catch (Exception e) {e.printStackTrace();} finally {if (conn != null) {conn.disconnect();}try {if (is != null) {is.close();}if (raf != null) {raf.close();}} catch (IOException e) {e.printStackTrace();}Log.i("test", "关闭一个下载任务");}super.run();}}
在这篇文章中的重点是使用了RandomAccessFile,它支持任意访问的方式,程序可以直接跳到任意地方来读写数据,RandomAccessFile的使用方式请查看《断点下载神器-RandomAccessFile》
《即拿即用-Android单线程断点下载》
《断点下载神器-RandomAccessFile》
《即拿即用-Android多线程断点下载》
完整代码地址
https://github.com/mocn26169/HttpRequest-Demo
参考
- Android实战:简易断点续传下载器实现
即拿即用-Android单线程断点下载相关推荐
- 即拿即用-Android多线程断点下载
线程下载只需要确定好下载一个文件需要多少个线程,一般来说最好为3条线程,因为线程过多会占用系统资源,而且线程间的相互竞争也会导致下载变慢. 其次下载的时候将文件分割为三份(假设用3条线程下载)下载,在 ...
- Android文件下载——单线程断点下载
文章目录 1. 相关逻辑 1.1 获取待下载文件的总长度 1.2 使用HTTP的Range头部字段 1.3 RandomAccessFile 1.4 添加监听接口 2. 调用示例 3. DownLoa ...
- android 多线程断点下载,listview 模式 开始 暂停等功能
android 多线程断点下载,listview 模式 代码依次如下: 布局: <?xml version="1.0" encoding="utf-8"? ...
- android 断点下载的实现,Android实现断点下载的方法
最近做的项目中需要实现断点下载,即用户一次下载可以分多次进行,下载过程可以中断,在目前大多数的带离线缓存的软件都是需要实现这一功能.本文阐述了通过sqlite3简单实现了一个具有断点下载功能的demo ...
- Android 多线程断点下载demo实现
先来一张效果图: 主要实现思路: 每一个下载都是通过RandomAccessFile对下载资源的总长进行切割之后,根据我们设置的线程多少进行计算之后开启多线程下载的.而每一个任务都是一个AsyncTa ...
- Android多线程断点下载
到华为后,信息管理特别严格,文件不能外发.所以好久都没写博客了,今天周日,老婆非要我学习.就闲来无事,写一篇博客,呵呵-- 前段时间,项目中提到了断点下载apk并静默安装的需求.本打算用应用市场成熟的 ...
- Android 多线程断点下载(非原创)
1.服务器的CPU分配给每条线程的时间片相同,服务器带宽平均分配给每条线程,所以客户端开启的线程越多,就能抢占到更多的服务器资源,这里在客户端开启多个线程来从服务器下载资源 2.fragment_ma ...
- Android中http断点下载,Android HttpURLConnection断点下载(单线程)
HttpCilent 跟 HttpURLConnection 是安卓原生的用来实现http请求的类: Android 6.0之后取消了HttpClient,不支持跟新 ,今天小编使用的是HttpURL ...
- Android之用HttpURLConnection断点下载谷歌云存储(google cloud storage)文件
1 需求 在Android app里面实现断点下载谷歌云存储(google cloud storage)文件,也就是说用户下载谷歌云存储(google cloud storage)文件的时候可以暂停下 ...
- android学习笔记---31_多线程断点下载器,下载原理实现
1.1.31_多线程断点下载器 ----------------------- 1.软件界面: 文件下载路径 text框 button 下载 点击后,下面显示下载 ...
最新文章
- 28岁女博士生被骂“学术媛”,只因在网上分享自己牛津年级第一成绩毕业......
- 想进大厂?Dubbo 普普通通 9 问你知道吗
- ios NSFileManager 用法详解
- 汇编解析(2)-内存寻址之实模型平面模式(real mode flat mode)(2)
- Windows中添加svnserve作为系统服务
- WPF之鼠标滑动切换图片
- 数据结构之排序算法Java实现(2)——选择类排序之堆排序算法
- Moonbox v0.3beta 发布:Grid 全新重构,更快更解耦
- 常用的排序算法(java版)
- excel进销存添加网页模块,可手机开单
- centos7 pe系统安装_CentOS 系统的安装
- osip和mysql_osip2/eXosip2调试笔记
- Unity 关于制作UV动画,模拟管路气路流向示意图
- 关于癌症的思考:癌症的本质是什么
- Linux基础命令的那些事儿(1)
- AE-摄影机和跟踪器
- Android Studio报错:E/EGL_emulation: tid 3197: eglSurfaceAttrib(1199): error 0x3009 (EGL_BAD_MATCH)
- jquery-weui扩展功能Picker实现营业时间选择
- “昆明城市咖啡地图”活动再度开启
- mac u盘linux 双系统安装教程,U盘安装MAC双系统完美方案实现在MAC系统下使用双系统...