Android 断点续传进阶之多线程下载
来源:互联网 发布:数据 集合提供商 编辑:程序博客网 时间:2024/05/12 15:45
今天继续下载的风骚走位内容---多线程多文件断点续传
Android 断点续传基础之单线程下载:http://blog.csdn.net/qq_27489007/article/details/53897653
效果图:
文件关系:
所需内容
多文件下载列表的显示
启动多个线程分段下载
使用通知栏显示进度条
使用其他方式实现线程通信
与单线程不主要不同:
任务下载类(DuoDownloadTask) 使用了线程池, 数据库对线程的增、删操作使用synchronized
多线程下载原理简介
假设要分3个线程下载一个100字节的文件,每个线程可以平分线程1(0-32字节)、 线程2(33-65字节)、线程3(66-100字节)
部分主要代码:
package com.example.test.service;import android.content.Context;import android.content.Intent;import com.example.test.DownloadDB.ThreadDAOImpl;import com.example.test.info.FileInfo;import com.example.test.info.TheardInfo;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;import java.util.ArrayList;import java.util.List;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * 多线程多文件的下载任务类,为了学习查看方便 所以提出来了 * Created by lung on 2016-12-17. */public class DuoDownloadTask { private Context mContext = null; private FileInfo mFileInfo = null; private ThreadDAOImpl mThreadDAO = null; private long mFinished = 0; //总的完成进度 public boolean isPause = false; //暂停下载的开关 private int mThreadCount = 1; //线程数量 private List<DownloadThread> downloadThreadList = null;//线程集合 方便管理 public static ExecutorService executorService = Executors.newCachedThreadPool();//线程池 public DuoDownloadTask(Context mContext, FileInfo mFileInfo, int mThreadCount) { this.mContext = mContext; this.mFileInfo = mFileInfo; this.mThreadCount = mThreadCount; mThreadDAO = new ThreadDAOImpl(mContext); } //下载的方法 public void download() { //读取数据库的线程信息 List<TheardInfo> 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.getEnd()); //设置文件写入位置 路径 文件名 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
package com.example.test.DownloadDB;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import com.example.test.info.TheardInfo;import java.util.ArrayList;import java.util.List;/** * 数据访问接口实现类 * 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<TheardInfo> getThreads(String url) { List<TheardInfo> 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)}); boolean isExist = cursor.moveToNext(); cursor.close(); db.close(); return isExist; }}
附上Demo:http://download.csdn.net/detail/qq_27489007/9722868
0 0
- Android 断点续传进阶之多线程下载
- Android之多线程下载及断点续传
- android开发之多线程下载断点续传
- android开发笔记之多线程下载及断点续传
- Android多线程系列之多线程下载之断点续传
- Android进阶:多线程断点续传下载
- Android 之多线程断点续传之(一)
- Android 之多线程下载原理
- Android之多线程断点下载
- Android 之多线程下载原理
- Android 断点续传基础之单线程下载
- android 多线程下载,断点续传,线程池
- androidj进阶之多线程
- Java进阶之多线程
- Java进阶之多线程
- Android中级篇之多线程下载
- Android实例demo18之多线程断点下载
- android开发之多线程断点下载
- tar 解压缩命令详解
- tensorflow笔记:模型的保存与训练过程可视化
- RHCE练习题 2. 配置防火墙对SSH的限制 两种方法
- 107. Binary Tree Level Order Traversal II
- 最小割模型——最大权闭合子图 【NOI2006】bzoj1497 最大获利
- Android 断点续传进阶之多线程下载
- JavaScrpt笔记之第三天
- PostgreSQL chinese full text search 中文全文检索
- RMQ问题----ST(Sparse-Table)算法
- 线性时间选择第k小(递归)
- IntelliJ Idea 常用快捷键 及 模板注释
- Qt中的键盘事件以及焦点设置
- 实体类编写规则与hibernate主键生成策略以及实体类三种状态
- 仅用作测试