Android 断点续传进阶之多线程下载

this.mThreadCount = mThreadCount;

mThreadDAO = new ThreadDAOImpl(mContext);

}

//下载的方法

public void download() {

//读取数据库的线程信息

List threaddInfos = mThreadDAO.getThreads(mFileInfo.getUrl());

if (threaddInfos.size() == 0) { //如果数据库无线程信息

//获得每个线程下载的长度

int length = mFileInfo.getLength() / mThreadCount;

for (int i = 0; i < mThreadCount; i++) {

// 参数三线程开始的地方 参数四 线程结束的地方 参数五任务完成的进度

TheardInfo theardInfo = new TheardInfo(i, mFileInfo.getUrl(), length * i, (i + 1) * length - 1, 0);

//最后一个线程 会出现除不尽的情况

if (i == mThreadCount - 1) {

//直接把线程的结束位置 设置成文件的最大长度位置

theardInfo.setEnd(mFileInfo.getLength());

}

//添加到线程信息集合中

threaddInfos.add(theardInfo);

//向数据库插入线程信息

mThreadDAO.insertThread(theardInfo);

}

}

downloadThreadList = new ArrayList<>();

//启动多个线程进行下载

for (TheardInfo info : threaddInfos) {

DownloadThread thread = new DownloadThread(info);

// thread.start(); //开始线程添加到集合中

DuoDownloadTask.executorService.execute(thread); //利用线程池来执行线程任务

downloadThreadList.add(thread); //把线程添加进去方便ckeckAllThreadFinshed检查线程

}

}

//这个方法 用来判断所有的线程是否都执行完了

private synchronized void checkAllThreadFinshed() {

boolean allFinished = true;

//遍历线程集合,判断线程是否都执行完毕

for (DownloadThread thread : downloadThreadList) {

if (!thread.isFinished) {

allFinished = false;

break;

}

}

if (allFinished) { //如果线程都完成了

//下载完成后 删除线程信息

//删除下载记录

mThreadDAO.deleteThread(mFileInfo.getUrl(), mFileInfo.getId());

//发送广播通知ui下载任务结束

Intent intent = new Intent(DuoDownloadService.ACTION_FINISHED);

intent.putExtra(“fileInfo”, mFileInfo);

mContext.sendBroadcast(intent); //发送广播

}

}

class DownloadThread extends Thread {

private TheardInfo threadInfo;

public boolean isFinished = false; //用来标识线程是否结束

public DownloadThread(TheardInfo threadInfo) {

this.threadInfo = threadInfo;

}

@Override

public void run() {

//设置下载位置

try {

URL url = new URL(threadInfo.getUrl());

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

conn.setRequestMethod(“GET”);

conn.setConnectTimeout(3000);

//开始的字节数 为开始加上完成的长度

long start = threadInfo.getStart() + threadInfo.getFinished();

//下载的范围 开始的字节数 到结束的字节数

conn.setRequestProperty(“Range”, “bytes=” + start + “-” + threadInfo.getEn​
d());

//设置文件写入位置 路径 文件名

File file = new File(DownloadService.DOWNLOAD_PATH, mFileInfo.getFileName());

//

RandomAccessFile raf = new RandomAccessFile(file, “rwd”);

raf.seek(start); //文件的写入位置

Intent intent = new Intent(DownloadService.ACTION_UPDATE);//把进度广播发送给activity 所以需要intent

mFinished += threadInfo.getFinished();//从线程中拿到完成的进度

//开始下载

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

//读取数据

InputStream input = conn.getInputStream();

byte[] buffer = new byte[1024 * 4];

int len = -1;

long time = System.currentTimeMillis(); //拿到当前时间

while ((len = input.read(buffer)) != -1) {

//写入文件

raf.write(buffer, 0, len);

//把下载进度发送广播给activity

mFinished += len; //把现在下载的进度累加进去

//累加每个线程完成的进度

threadInfo.setFinished(threadInfo.getFinished() + len);

if (System.currentTimeMillis() - time > 1000) { //减少ni负载 大于10秒发送更新

time = System.currentTimeMillis();

//以百分比的形式发送给广播

intent.putExtra(“finished”, (int) (mFinished * 100 / mFileInfo.getLength()));

intent.putExtra(“id”, mFileInfo.getId());

mContext.sendBroadcast(intent);

}

//在下载暂停时,保存下载进度

if (isPause) { //如果暂停 把线程信息进行保存 最后一个参数 他会把每个线程的 进度保存起来

mThreadDAO.updateThread(mFileInfo.getUrl(), mFileInfo.getId(), threadInfo.getFinished());

return;

}

}

intent.putExtra(“finished”, 100);

mContext.sendBroadcast(intent); //发送广播

// 标识线程执行完毕

isFinished = true;

//每个线程执行完毕 都执行去判断 所有的线程是否都执行完毕

checkAllThreadFinshed();

input.close();

}

raf.close();

conn.disconnect();

} catch (MalformedURLException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally { //关闭各种链接

}

super.run();

}

}

}

ThreadDAOImpl.java

/**

  • 数据访问接口实现类

  • Created by lung on 2016-12-07.

*/

public class ThreadDAOImpl implements ThreadDAO {

private DBHelper mHelper=null;

public ThreadDAOImpl(Context context){

mHelper=DBHelper.getInstance(context);

}

//插入线程信息

@Override

public synchronized void insertThread(TheardInfo threadInfo) { //加锁进行同步

SQLiteDatabase db=mHelper.getWritableDatabase();//获得可写的数据库

db.execSQL(“insert into thread_info(thread_id,url,start,end,finished) values(?,?,?,?,?)”,new Object[]{threadInfo.getId(), threadInfo.getUrl(),

threadInfo.getStart(), threadInfo.getEnd(), threadInfo.getFinished()});

db.close();

}

//删除线程

@Override

public synchronized void deleteThread(String url, int thread_id) {

SQLiteDatabase db=mHelper.getWritableDatabase();//获得可写的数据库

db.execSQL(“delete from thread_info where url = ? and thread_id=?”,

new Object[]{url, thread_id});

db.close();

}

//更新线程下载进度

@Override

public synchronized void updateThread(String url, int thread_id, long finished) {

SQLiteDatabase db=mHelper.getWritableDatabase();//获得可写的数据库

db.execSQL(“update thread_info set finished = ? where url = ? and thread_id=?”,

new Object[]{finished, url, thread_id});

db.close();

}

//查询文件的线程信息

@Override

public List getThreads(String url) {

List list = new ArrayList<>();

SQLiteDatabase db = mHelper.getWritableDatabase();

Cursor cursor = db.rawQuery(“select * from thread_info where url=?”, new String[]{url});

while (cursor.moveToNext()) {

TheardInfo thread = new TheardInfo();

thread.setId(cursor.getInt(cursor.getColumnIndex(“thread_id”)));

thread.setUrl(cursor.getString(cursor.getColumnIndex(“url”)));

thread.setStart(cursor.getInt(cursor.getColumnIndex(“start”)));

thread.setEnd(cursor.getInt(cursor.getColumnIndex(“end”)));

thread.setFinished(cursor.getInt(cursor.getColumnIndex(“finished”)));

list.add(thread);

}

cursor.close();

db.close();

return list;

}

@Override

public boolean isExists(String url, int thread_id) {

SQLiteDatabase db = mHelper.getReadableDatabase();

Cursor cursor = db.rawQuery(“select * from thread_info where url=? and thread_id = ?”,

new String[]{url, String.valueOf(thread_id)});

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取
rom thread_info where url=? and thread_id = ?",

new String[]{url, String.valueOf(thread_id)});

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

[外链图片转存中…(img-qwomAKfv-1719080542870)]一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值