Android多线程断点续传下载
2015-06-02 16:33
369 查看
在上一篇文章
Java、Android中的多线程异步下载 中并没有完成断点续传的功能。
所谓的断点续传,主要就是使用一个记录下载进度的文件,每次下载开始时,先判断进度文件是否存在,并读取其中的进度。
下面的代码就是在Android上实现短线续传下载功能的代码:
整个代码与Java、Android中的多线程异步下载中代码的主要区别就是多了一个进度文件的处理功能。
在这个例子中每个线程都生成了一个自己的进度文件,下载完成则删除进度文件,在实际中,比方说迅雷下载的时候,这个文件只生成一个的。
由于多个文件的存在,会产生一些问题,必须同步删除进度文件。
以上代码基本上把断点续传的原理都展示的很清楚了。
工作的流程如图所示。
Java、Android中的多线程异步下载 中并没有完成断点续传的功能。
所谓的断点续传,主要就是使用一个记录下载进度的文件,每次下载开始时,先判断进度文件是否存在,并读取其中的进度。
下面的代码就是在Android上实现短线续传下载功能的代码:
package test.multdownload; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ProgressBar; import com.fc.rssreader.R; public class MultDownloadActivity extends Activity { private Button downloadButton; private ProgressBar pb; public int threadCount = 3; public String path = "http://dldir1.qq.com/qqfile/qq/QQ7.2/14810/QQ7.2.exe"; // public String // path="http://hiphotos.baidu.com/240728057/pic/item/6a50e38242aad8f60cf4d2b3.jpg"; int threadFinish = 0; int currentProgress=0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_mult_download); downloadButton = (Button) findViewById(R.id.download); pb = (ProgressBar) findViewById(R.id.pb); downloadButton.setOnClickListener(listener); } private OnClickListener listener = new Button.OnClickListener() { @Override public void onClick(View v) { Thread t = new Thread() { public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url .openConnection(); conn.setRequestMethod("GET"); conn.setReadTimeout(5000); conn.setConnectTimeout(5000); if (conn.getResponseCode() == 200) { // 下载文件的大小 int length = conn.getContentLength(); // 创建临时文件的路径和名称 File file = new File("sdcard/"+getFileName(path)); // 创建速记存储文件对象 RandomAccessFile raf = new RandomAccessFile(file, "rwd"); // 设置临时文件大小 raf.setLength(length); //给进度条的最大进度设置原文件总大小 pb.setMax(length); // 计算每个线程下载的字节数 int size = length / threadCount; for (int i = 0; i < threadCount; i++) { // 计算每个线程下载数据的开始和结束位置 int startIndex = i * size; int endIndex = (i + 1) * size - 1; // 如果是最后一个线程,那么借宿位置特殊处理 if (i == threadCount - 1) { endIndex = length - 1; } System.out.println("线程" + i + "已经启动,下载位置为:" + startIndex + "--------->" + endIndex); // 开始线程 new DownloadThread(i, startIndex, endIndex, url) .start(); } } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } }; }; t.start(); } }; public static String getFileName(String path) { int index = path.lastIndexOf("/"); return path.substring(index + 1); } /** * @author frozen cloud 下载线程 */ class DownloadThread extends Thread { int threadId; int startIndex; int endIndex; URL url; public DownloadThread(int threadId, int startIndex, int endIndex, URL url) { super(); this.threadId = threadId; this.startIndex = startIndex; this.endIndex = endIndex; this.url = url; } @Override public void run() { try { // 设置记录下载进度的临时文件的路径和名称 File fileProgress = new File("sdcard/"+threadId + ".txt"); // 判断保存下载进度的临时文件是否存在 if (fileProgress.exists()) { FileInputStream fis = new FileInputStream(fileProgress); BufferedReader br = new BufferedReader( new InputStreamReader(fis)); int newStartIndex = Integer.parseInt(br.readLine()); currentProgress += (newStartIndex - startIndex); pb.setProgress(currentProgress); startIndex = newStartIndex; fis.close(); } System.out.println("线程" + threadId + "最终开始位置:" + startIndex); HttpURLConnection conn = (HttpURLConnection) url .openConnection(); conn.setRequestMethod("GET"); conn.setReadTimeout(5000); conn.setConnectTimeout(5000); // 设置请求的数据的范围 conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); if (conn.getResponseCode() == 206) { InputStream is = conn.getInputStream(); int len = 0; byte[] b = new byte[1024]; int total = 0; // 创建临时文件的路径和名称 File file = new File("sdcard/"+getFileName(path)); // 创建速记存储文件对象 RandomAccessFile raf = new RandomAccessFile(file, "rwd"); // 设置线程写入数据的开始位置 raf.seek(startIndex); // 记录当前下载进度 int currentPosition = startIndex; while ((len = is.read(b)) != -1) { // 下载文件 raf.write(b, 0, len); // 下载进度 total += len; RandomAccessFile rafProgress = new RandomAccessFile( fileProgress, "rwd"); currentPosition = startIndex + total; rafProgress.write((currentPosition + "").getBytes()); rafProgress.close(); // System.out.println("线程"+threadId+"总共下载了:"+total); //每次下载len个长度的字节,都把字节设置到进度条的进度中 currentProgress += len; pb.setProgress(currentPosition); } raf.close(); System.out.println("线程下载结束:" + threadId); threadFinish++; // 如果这个条件成立,说明所有线程下载完毕 synchronized (path) { if (threadFinish == threadCount) { for (int i = 0; i < threadCount; i++) { File temp = new File("sdcard/"+i + ".txt"); temp.delete(); } threadFinish = 0; } } } } catch (Exception e) { e.printStackTrace(); } } } }
整个代码与Java、Android中的多线程异步下载中代码的主要区别就是多了一个进度文件的处理功能。
在这个例子中每个线程都生成了一个自己的进度文件,下载完成则删除进度文件,在实际中,比方说迅雷下载的时候,这个文件只生成一个的。
由于多个文件的存在,会产生一些问题,必须同步删除进度文件。
以上代码基本上把断点续传的原理都展示的很清楚了。
工作的流程如图所示。
相关文章推荐
- AndroidManifest.xml——文件详解(一)
- #Android 自定义字体样式
- Android进步之路六:android限制横竖屏切换的方法
- Android APK反编译就这么简单 详解(附图)
- Android项目实战-云词典
- android数据保存
- Android 获取外置SD卡
- Android studio 安装中遇到一些问题的解决办法
- Android 限制EditText只能输入数字、限制输入类型、限制输入长度的小技巧
- android中一些简单的布局
- 去除Android系统应用的通知功能
- 【Rayeager PX2分享】最简单helloworld驱动编写
- Android与IOS的后台与推送对比
- Android系统介绍
- android 中文 api (64) —— Scroller
- Android r文件丢失的解决办法
- android SharedPreferences设置初始密码,并修改密码
- JAVA ANDROID SOCKET通信检测(SERVER)连接是否断开
- android获取屏幕宽高与获取控件宽高
- android中的ellipsize