Android 下载线程的编写
来源:互联网 发布:网络电视如何看地方台 编辑:程序博客网 时间:2024/05/17 18:48
在我们的开发中,碰到文件下载的情况已经是很多见了吧?平时在开发大项目时,我们可能会用一些开源的库,比如afinal、Xutils等等,不过对于一些菜鸟的学习来说,自己去写一个下载的工具类,这对于自身的知识巩固那还是有很多好处的。好了废话不多说,现在我们直接来写一个文件下载工具类(不支持断点续传)。
下面我们来分析一下怎么去写。
首先,我们得去发送http请求去加载我们的inputStream吧,其次我们还得去利用BufferedInputStream、BufferedOutputStream等去写文件吧,还有md5校验吧。好了这里边还有很多细节问题,我们来一一查看,直接上代码。
// 获取文件的inputStreamprivate InputStream getInputStream(String path)throws Exception {listener.statusListener(0,this.getFileName());URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(10 * 1000);conn.setRequestMethod("GET");if(length <= 0){try {Map<String, List<String>> map = conn.getHeaderFields();for(int i=0;i<map.size();i++){if(map.containsKey("Content-Length")){String temp = map.get("Content-Length").toString().replaceAll("\\]", "").replaceAll("\\[", "");length = Long.parseLong(temp);break;}}} catch (Exception e) {length = 0;}}if(length <= 0){listener.statusListener(-1,this.getFileName());return null;}if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {return conn.getInputStream();}return null;}
根据上面的代码块我们来分析,HttpURLConnection去拿我们想要的数据,包括http头和inputStream,在http头里边有我们下载文件的长度,这个长度可以用来检测下载成功与否和下载进度的显示。这个方法我们返回的是一个inputStream。
在线程run方法里边有一个while循环,在循环里去获取inputStream,因为有可能我们获取到的inputStream为null,所以我们循环获取,最多获取三次。
while (isRunning && errorCount < 3) {threadStartRun = true;if(errorCount >= 2){listener.statusListener( -1,this.getFileName());break;}try {inputStream = getInputStream(src);if(inputStream == null){errorCount++;Thread.sleep(3000);continue;}} catch (Exception e) {e.printStackTrace();errorCount++;continue;}if(inputStream !=null){break;}}拿到inputStream之后当然是去读写文件到本地.
/** * 将InputStream保存为本地文件 * */private String saveFile(InputStream is) throws IOException {threadStartWrite = true;File myCaptureFile = new File(this.getFileName());if (myCaptureFile.exists()) {myCaptureFile.delete();}myCaptureFile.createNewFile();FileOutputStream out = null;try {out = new FileOutputStream(myCaptureFile);BufferedInputStream bufis = new BufferedInputStream(is);BufferedOutputStream bufos = new BufferedOutputStream(out);byte[] b = new byte[1024*16];int len;long count = 0;float process = 0;while (isRunning && (len = bufis.read(b)) != -1) {bufos.write(b, 0, len);count += len;process =(float)count/length*100;if(!isRunning){break;}getListener().statusListener((int)process,myCaptureFile.getAbsolutePath());downprocess = (int)process;N = (int) count;}out.flush();bufis.close();bufos.close();if(!isRunning){return null;}String tempMd5 = getFileMD5(myCaptureFile);if(!(getMd5().equals(tempMd5))){N = -1;downprocess = -1;return null;}return myCaptureFile.getAbsolutePath();} catch (Exception e) {getListener().statusListener(-1,myCaptureFile.getAbsolutePath());N = -1;downprocess = -1;return null;}}从上面代码块我们可以看到,获取到inputStream之后利用BufferedInputStream等去写文件,当然还有一个重要方法就是getListener().statusListener((int)process, myCaptureFile. getAbsolutePath());通知调用者当前下载的进度。
下载完成之后会有一个md5码的校验,直接来代码。若返回为null校验失败,否则下载成功。
private String getFileMD5(File file) {if (!file.isFile()) {return null;}MessageDigest digest = null;FileInputStream in = null;byte buffer[] = new byte[1024];int len;try {digest = MessageDigest.getInstance("MD5");in = new FileInputStream(file);while ((len = in.read(buffer, 0, 1024)) != -1) {digest.update(buffer, 0, len);}in.close();} catch (Exception e) {e.printStackTrace();return null;}BigInteger bigInt = new BigInteger(1, digest.digest());String strMd5 = bigInt.toString(16);if (strMd5.length() < 32) {for (int i = 0; i < 32 - strMd5.length(); i++) {strMd5 = "0" + strMd5;}}return strMd5;}当然下载完成之后我们还得通知调用者下载完成吧。
getListener().statusListener(100,myCaptureFile.getAbsolutePath());
好了,下载的线程算是完事了,我们的额超时线程还没完呢,等等,别着急马上。它主要是干啥呢,就是检测下载线程的运行状态,来吧那就。
@Overridepublic void run() {super.run();name = downloadTask.getFileName();try {while(!downloadTask.isThreadStartRun()&& downloadTask.isRunning()){ //开始启动下载的时候 ,超时线程也跟着启动。Thread.sleep(500);}if(downloadTask.isRunning()){isWhile = true;}Thread.sleep(2000);while(downloadTask != null && downloadTask.isRunning()) {isWhile = true;Thread.sleep(3000);if(c != downloadTask.getN() && downloadTask.isThreadStartWrite() && c!=downloadTask.getLength()) {c = downloadTask.getN();t=0;process = downloadTask.getDownprocess();} else {if(process<100)t++;}process = downloadTask.getDownprocess();if(process > 100){break;}if(t >= TIMEOUT_COUNT) {downloadTask.setRunning(false);downloadTask.interrupt();downloadTask = null;break;}if(process <= -1){break;}}if(t >= TIMEOUT_COUNT && downloadTask == null && process<100) {listener.statusTimeoutListener(-1,name);return;}if(!isWhile){if(downloadTask != null){downloadTask.setRunning(false);downloadTask.interrupt();downloadTask = null;}listener.statusTimeoutListener(-1,name);}} catch (Exception e) {if(process <100){listener.statusTimeoutListener(process,name);}}
这是它的一个run方法,可以看到首先,做一个延时,等待下载线程的执行,因为我们的超时线程和下载线程必须同时执行!!随之来的就是检测,检测下载线程的isRunning,检测文件读写是是否卡顿,如果在12s之内下载一直是卡顿的,我们就直接将下载线程停止掉(当然,这个停止掉指的是我们不再使用它,并不能直接杀死他),这个12秒我们也可以自己在超时线程里边控制。如果 listener.statusTimeoutListener(process,name);则表示线程下载超时,停止下载。
使用方法:
DownloadTask downloadTask = new DownloadTask("下载地址", "文件md5", 122222, "文件保存地址", new DownloadTask.DownLoadTaskStatusListener() <span style="white-space:pre"></span>{public void statusListener(int process, String fileName) {// 这里边是下载进度的回调}});downloadTask.start();DownloadTimeout downloadTimeout = new DownloadTimeout(downloadTask, new DownLoadTaskStatusTimeoutListener() {public void statusTimeoutListener(int process, String fileName) {// 这里边是下载失败,超时的回调}});downloadTimeout.start();
当然咯,下面就是下载链接了 点击打开链接 下载。
2 0
- Android 下载线程的编写
- Android 线程编写方式之一
- [android] android源码中的下载线程的实现
- Android第九讲——网络(四) 文件的下载(单线程下载、多线程下载)
- Android实现单线程异步多文件下载的代码
- Android实现单线程异步多文件下载的代码
- Android 实现文件的单线程断点续传下载
- Android 单线程下载与多线程下载
- Android 之多线程下载原理
- Android之多线程断点下载
- Android 之多线程下载原理
- 编写线程安全的JSP
- 编写线程安全的代码
- 编写线程安全的方法
- 编写线程安全的代码
- android 编写简单浏览器带下载
- 线程下载图片的问题
- 自己编写的简单的线程池
- Java的native方法
- 微软再度发力搜索业务:全力以赴挑战谷歌
- 酷秀网业务梳理
- php 配置 mcrypt模块
- web开发者推荐的最佳HTML5/CSS3代码生成器
- Android 下载线程的编写
- 基于SpringMVC Annotation配置的HelloWorld
- 谷歌再出手 将三字母域名abc.biz收至麾
- win10 uwp 参考
- 整理一下最近的收获,java中接口的使用
- VS调试时JSON格式文件加载不了
- 常见的Xcode运行障碍及解决方案
- sql developer中的dbms_output.put_line不能输出结果
- MySQL 入门教程