android多线程断点,Android实现断点多线程下载

断点多线程下载的几个关键点:①:得到要下载的文件大小后,均分给几个线程。②:使用RandomAccessFile类进行读写,可以指定开始写入的位置。③:数据库保存下载信息,下一次继续下载的时候从数据库取出数据,然后从上次下载结束的地方开始。

这里我使用了FinalDb的数据库框架,同时在内存中存储了一份所有线程的下载信息,负责时时更新和查询下载进度。我测试用的是百度云网盘,文件大小50M左右。注意,线程中指定了开始结束下载位置的网络请求成功的返回码是206,并不是200。

效果图:

a3dec7c9a0a46715770cbb2f87ff8274.png

线程类:线程类负责具体的下载,线程的下载信息被存储到了数据库。线程开始下载时,根据线程ID查询自己的存储信息,然后开始从指定的位置下载和写入文件。完毕后根据自己的当前下载结果设置自己当前的下载状态。时时的下载进度存储只存储到了内存,只在本次下载结束才存储到数据库。

public class DownloadThread extends Thread {

/**

* 数据库操作工具

*/

private FinalDb finalDb;

/**

* 下载状态:未开始

*/

public static final int STATE_READY = 1;

/**

* 下载状态:下载中

*/

public static final int STATE_LOADING = 2;

/**

* 下载状态:下载暂停中

*/

public static final int STATE_PAUSING = 3;

/**

* 下载状态:下载完成

*/

public static final int STATE_FINISH = 4;

/**

* 下载状态

*/

public int downloadState;

/**

* 线程ID

*/

private int threadID;

/**

* 要下载的URL路径

*/

private String url;

/**

* 本线程要下载的文件

*/

public RandomAccessFile file;

/**

* 构造器

*/

public DownloadThread(Context context, int threadID, String downloadUrl, RandomAccessFile randomAccessFile) {

this.threadID = threadID;

this.url = downloadUrl;

this.file = randomAccessFile;

finalDb = DBUtil.getFinalDb(context);

}

@Override

public void run() {

//数据库查询本线程下载进度

List list = finalDb.findAllByWhere(ThreadDownloadInfoBean.class, "threadID='" + threadID + "'");

//下载信息存放到内存

if (list.get(0) != null) {

MapUtil.map.put(threadID, list.get(0));

}

//取出实体类

ThreadDownloadInfoBean bean = MapUtil.map.get(threadID);

Utils.Print("bean:" + bean.toString());

InputStream is;

HttpURLConnection conn;

try {

Utils.Print("线程" + threadID + "开始连接");

conn = (HttpURLConnection) new URL(url).openConnection();

conn.setConnectTimeout(5000);

conn.setReadTimeout(5000);

conn.setRequestMethod("GET");

//设置下载开始和结束的位置

conn.setRequestProperty("Range", "bytes=" + (bean.startDownloadPosition + bean.downloadedSize) + "-" + bean.endDownloadPosition);

conn.connect();

if (conn.getResponseCode() == 206) {

//更改下载状态

downloadState = STATE_LOADING;

bean.downloadState = STATE_LOADING;

Utils.Print("线程" + threadID + "连接成功");

is = conn.getInputStream();

// 1K的数据缓冲

byte[] bs = new byte[1024];

// 读取到的数据长度

int len;

//从指定的位置开始下载

file.seek(bean.startDownloadPosition);

// 循环读取,当已经下载的大小达到了指定的本线程负责的大小时跳出循环,线程之间负责的文件首尾有重合的话没有影响,因为写入的内容时相同的

while ((len = is.read(bs)) != -1) {

//不用在这个循环里面更新数据库

file.write(bs, 0, len);

//时时更新内存中的已下载大小信息

bean.downloadedSize += len;

//如果调用者暂停下载,则跳出结束方法

if (downloadState == STATE_PAUSING) {

Utils.Print("线程" + threadID + "暂停下载");

break;

}

}

is.close();

file.close();

} else {

Utils.Print("线程" + threadID + "连接失败");

}

conn.disconnect();

//如果这个线程已经下载完了自己负责的部分就修改下载状态

if (bean.downloadedSize >= bean.downloadTotalSize) {

bean.downloadState = STATE_FINISH;

} else {

bean.downloadState = STATE_PAUSING;

}

//内存中信息更新至数据库

finalDb.update(bean, "threadID='" + bean.threadID + "'");

} catch (IOException e) {

Utils.Print("线程" + threadID + "IO异常");

e.printStackTrace();

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值