kill应用以后,android断点续传的实现
来源:互联网 发布:银行业大数据 编辑:程序博客网 时间:2024/05/15 18:15
看了网上很多关于Android断点续传的文章,方法多样,但是涉及断网、断电、kill掉应用的情况却很少。因为我在的公司做的是盒子游戏,通过一个Android系统的机顶盒,用来在Unity3D和服务器之间进行通。老板要求更新APP应用的时候,在wifi断开或者盒子突然断电,重新打开应用的时候,要求继续更新而不是重新下载。这个问题困恼了我几天,最后参考了http://blog.csdn.net/a1533588867/article/details/53129259 这篇博客的内容,并且对他的源码进行一定的修改,也算是完成了老板的需求。万分感谢这位博主!
kill应用的原理和断电的情况一致,经过测试,也是没问题的。其实,断电也就相当于用户把在后台运行的应用强制关闭。
当出现异常的时候,比如wifi断开或者断电了,在开启下载线程之后,HttpURLConnection 连接网络之前,对临时文件进行操作,如果临时文件存在,就暂停下载线程,并且开启文件拼接线程,将临时文件拼接在总文件中,拼接完以后,删除临时文件,开启下载线程继续下载。大致就是这样。对于如何初始化线程,如何保存进度,如何分发和接受下载进度,如何管理下载线程等都在上面那篇博客讲到了,还挺详细的,我就不多做描述。
下面贴出一些核心代码,便于理解。
这是下载线程。
public class DownloadThread extends Thread { private FileBean fileBean; private ThreadBean threadBean; private DownloadCallBack callback; private Boolean isPause = false; private Context mContext; private final int divisionLen = 1024 * 1024 * 5; private boolean downloadOver = false; public DownloadThread(FileBean fileBean, ThreadBean threadBean, DownloadCallBack callback, Context mContext) { this.fileBean = fileBean; this.threadBean = threadBean; this.callback = callback; this.mContext = mContext; } public void setPause(Boolean pause) { isPause = pause; } @Override public void run() { HttpURLConnection connection = null; FileOutputStream fos = null; InputStream inputStream = null; //设置下载起始位置 int start = threadBean.getStart() + threadBean.getFinished(); String sp_tempFileName = Utils.getShardPreferences(mContext, "tempFileName"); Log.e("tag", "sp_tempFileName = " + sp_tempFileName); if (sp_tempFileName != null) { Log.e("tag", "sp中存在存在tempFileName"); File sp_tempFile = new File(Config.downLoadPath,sp_tempFileName); //处理上次没有下载完的文件 if (sp_tempFile.exists() && sp_tempFile.length() <= divisionLen) { Log.e("tag", "上次没有下载完的文件:"+sp_tempFileName+",长度为: " + sp_tempFile.length()); //调用暂停下载方法,销毁 下载线程 // 一定要先调用暂停方法,去销毁下载线程,再开启 文件拼接的线程。 //因为断电的时候,临时文件的大小有可能为0KB,导致如果先开启文件拼接的线程,拼接过程瞬间完成, // 使得下载线程可能还没销毁完成,就开启了下载线程,然后下载线程又被销毁 Utils.pauseDownload(mContext,fileBean); new AddFileThread(sp_tempFileName, fileBean, start, (int) sp_tempFile.length(), mContext, false).start(); threadBean.setFinished((int) (threadBean.getFinished() + sp_tempFile.length())); //修改进度 callback.pauseCallBack(threadBean); return; } } else { Log.e("tag", "不存在 tempFileName 说明是第一次"); } try { URL url = new URL(threadBean.getUrl()); connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(10000); connection.setRequestMethod("GET"); connection.setRequestProperty("Range", "bytes=" + start + "-" + threadBean.getEnd()); //设置写入位置 写入临时文件 String tempFileName = System.currentTimeMillis() + "tempFile"; Utils.setShardPreferences(mContext, "tempFileName", tempFileName); File tempFile = new File(Config.downLoadPath, tempFileName); fos = new FileOutputStream(tempFile); //开始下载 if (connection.getResponseCode() == HttpURLConnection.HTTP_PARTIAL) { inputStream = connection.getInputStream(); byte[] bytes = new byte[1024]; int len = -1; int subsLen = 0; Log.e("tag", "---开始下载---"); while (subsLen < divisionLen) { len = inputStream.read(bytes); //下载完毕 退出循环 if (len < 0) { Log.e("tag", "下载完毕,退出循环"); downloadOver = true; break; } //下载达到分次下载量 退出循环 if ((subsLen + len) > divisionLen) { Log.e("tag", "达到分批下载量,退出循环 countLen = " + subsLen); break; } if (isPause){ //调用暂停下载方法,销毁 下载线程 Log.e("tag", "调用暂停下载方法,销毁下载线程"); Utils.pauseDownload(mContext,fileBean); break; } fos.write(bytes, 0, len); subsLen += len; //将加载的进度回调出去 callback.progressCallBack(len); } if (!isPause){ // 对于整个文件 一共下载的进度。保存进度 int lengthCount = threadBean.getFinished() + subsLen; threadBean.setFinished(lengthCount); //分批下载完,需要将数据保存到数据库 callback.pauseCallBack(threadBean); Log.e("tag", "一共下载了:lengthCount = " + lengthCount); //这里因为文件需要进行拼接 5M 是一个耗时过程,所以 销毁下载线程 和 开启 文件拼接线程 的顺序可先可后 //调用暂停下载方法,销毁 下载线程 Utils.pauseDownload(mContext,fileBean); //开启线程 进行文件的拼接 new AddFileThread(tempFileName, fileBean, start, subsLen, mContext, downloadOver).start(); } //下载完成 if (downloadOver) { callback.threadDownLoadFinished(threadBean); } } } catch (Exception e) { //当断网的时候,会抛出连接超时异常,所以要在 catch 里回调 pauseCallBack 接口,进行数据的保存 Log.e("tag", "调用暂停下载方法,销毁下载线程"); Utils.pauseDownload(mContext,fileBean); } finally { try { inputStream.close(); fos.close(); connection.disconnect(); } catch (Exception e) { Log.e("tag", "Exception-111--" + e.getMessage()); } } }}
public class AddFileThread extends Thread { private String tempFileName; private FileBean fileBean; private int filePointer; private int downloadLen; private Context context; private boolean downloadOver; /** * @param tempFileName 临时文件名 * @param filePointer 从文件的哪里拼接 * @param downloadLen 拼接的长度 * @param downloadOver 是否下载完 */ public AddFileThread(String tempFileName, FileBean fileBean, int filePointer, int downloadLen, Context context,boolean downloadOver){ this.tempFileName = tempFileName; this.fileBean = fileBean; this.filePointer = filePointer; this.downloadLen = downloadLen; this.context = context; this.downloadOver = downloadOver; } @Override public void run() { super.run(); File file = new File(Config.downLoadPath,fileBean.getFileName()); File tempFile = new File(Config.downLoadPath,tempFileName); RandomAccessFile raf = null; FileInputStream fis =null; try { raf = new RandomAccessFile(file,"rw"); raf.seek(filePointer); fis = new FileInputStream(tempFile); Log.e("tag","拼接文件的线程:临时文件 tempFile.length() = "+tempFile.length()); int len = -1; int countLen = 0; byte buf[] = new byte[1024]; while(countLen < downloadLen){ len = fis.read(buf); countLen += len; raf.write(buf,0,len); //处理最后一点字节 if((countLen + 1024) > downloadLen){ byte buff[] = new byte[downloadLen - countLen]; len = fis.read(buff); Log.e("tag","最后一次读取的长度为:" + len); raf.write(buff,0,len); break; } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { raf.close(); fis.close(); } catch (IOException e) { Log.e("tag","Exception --- "+e.getMessage()); } } //删除临时文件 tempFile.delete(); //开启下载线程 接着去下载文件 if (!downloadOver){ Log.e("tag","继续下载"); Utils.startDownload(context,fileBean); } }}
因为文件拼接的过程是一个耗时的操作,但是拼接速度很快大概200ms,基本可以忽略不计。如果你运气是真的好,在200ms的文件拼接过程中,kill掉了应用或者断电了,拼接过程中断,下载完成以后,apk安装包解析不会出错,但是会出现安装更新失败的情况。如果真的出现了,快去买一张彩票!说不定呢,对吧!
附上测试拼接文件过程所耗费的时间(这里拼接的文件大小为10M):
保留了自己调试的一些Log,应该没太大问题吧。其余代码都和那位博主的源码差不多。
如果有下载完apk文件,自动安装的话,在下载线程中要稍作修改。
//下载完成 if (downloadOver) { callback.threadDownLoadFinished(threadBean); }
这里应该修改成:
AddFileThread addFileThread = new AddFileThread(tempFileName, fileBean, start, subsLen, mContext, downloadOver); addFileThread.start(); //下载完成 if (downloadOver) { while (true){ //必须等待 文件拼接线程结束才可以去回调接口通知下完完毕 //否则可能会出现 文件还没拼接完毕,就调用了安装apk文件的方法, // 导致出现apk解析错误 if (!addFileThread.isAlive()){ callback.threadDownLoadFinished(threadBean); break; } } }
最后提一下,那位博主的demo支持多线程下载,我的应该不支持,我没去调试。然后,那个暂停按钮可能存在一点bug,同样的代码测试着测试着就没问题了[费解][费解]因为我的需求里不需要暂停按钮,就没有多做研究,个人觉得没有太大问题。
最后附上我的源码:http://download.csdn.net/download/baidu_35697065/9933925
阅读全文
1 0
- kill应用以后,android断点续传的实现
- Kill应用之后断点续传的实现
- Android断点续传的实现
- kill掉android应用的bat
- kill掉android应用的bat
- android应用被kill的处理
- android端的断点续传的实现
- [Android]网络资源下载时断点续传的实现
- [Android]网络资源下载时断点续传的实现
- [Android]网络资源下载时断点续传的实现
- [Android]网络资源下载时断点续传的实现
- Android多线程断点续传下载的实现
- [Android]网络资源下载时断点续传的实现
- Android多线程断点续传下载的实现
- Android平台HTTP断点续传的实现
- android断点续传下载实现的大致思路
- android实现断点续传
- Android断点续传实现
- Theme Section
- 算法题/两个队列实现栈
- gl_LightSource[n].position
- 制作淘宝搜索框,js选择店铺、宝贝
- 何为OOP.....
- kill应用以后,android断点续传的实现
- Android 监听外部U盘插入
- 机器学习校招笔记3:集成学习之Adaboost
- Python框架、库和软件资源大全
- Fiddler简介
- 慕课笔记--[课程]Grunt-beginner 前端自动化工具
- 第三部分 数据结构(一)
- Java集合---HashMap源码剖析
- 有可直接运营的IPTV/OTT系统ma?