OkDownload是一款多线程断点续传下载引擎,它的功能完整,性能高,可配置性高,可以注入自定义组件来修改下载策略、替换网络请求框架等等,而且在项目中已有成熟应用(英语流利说),是一个很不错的开源下载框架。
OkDownload的简单使用
OkDownload的使用非常简单:
1.引入该开源库:
implementation 'com.liulishuo.okdownload:okhttp:1.0.5' (提供okhttp连接,ps:如果使用的话,需要引入okhttp网络请求库)
implementation 'com.liulishuo.okdownload:okdownload:1.0.5' (下载核心库)
implementation 'com.liulishuo.okdownload:sqlite:1.0.5' (存储断点信息的数据库)
2.开始一个任务:
task = new DownloadTask.Builder(url, parentFile)
.setFilename(filename)
// 下载进度回调的间隔时间(毫秒)
.setMinIntervalMillisCallbackProcess(30)
// 任务过去已完成是否要重新下载
.setPassIfAlreadyCompleted(false)
.build();
//异步执行任务
task.enqueue(listener);
// 取消任务
task.cancel();
// 同步执行任务
task.execute(listener);
当然也可以同时异步执行多个任务
DownloadTask.enqueue(tasks, listener);
3.任务队列的构建、开始和停止
DownloadContext.Builder builder = new DownloadContext.QueueSet()
.setParentPathFile(parentFile)
.setMinIntervalMillisCallbackProcess(150)
.commit();
builder.bind(url1);
builder.bind(url2).addTag(key, value);
builder.bind(url3).setTag(tag);
builder.setListener(contextListener);
DownloadTask task = new DownloadTask.Builder(url4, parentFile)
.setPriority(10).build();
builder.bindSetTask(task);
DownloadContext context = builder.build();
context.startOnParallel(listener);
// stop
context.stop();
4.获取任务状态
Status status = StatusUtil.getStatus(task)
status = StatusUtil.getStatus(url, parentPath, null);
status = StatusUtil.getStatus(url, parentPath, filename);
boolean isCompleted = StatusUtil.isCompleted(task);
isCompleted = StatusUtil.isCompleted(url, parentPath, null);
isCompleted = StatusUtil.isCompleted(url, parentPath, filename);
Status completedOrUnknown = StatusUtil.isCompletedOrUnknown(task);
5.获取断点信息
// 注意:任务完成后,断点信息将会被删除
BreakpointInfo info = OkDownload.with().breakpointStore().get(id);
info = StatusUtil.getCurrentInfo(url, parentPath, null);
info = StatusUtil.getCurrentInfo(url, parentPath, filename);
// 断点信息将被缓存在任务对象中,即使任务已经完成了
info = task.getInfo();
6.设置任务监听
可以为任务设置五种不同类型的监听器,同时,也可以给任务和监听器建立1对1、1对多、多对1、多对多的关联。
给一个任务设置多种监听:
DownloadListener listener1 = new DownloadListener1();
DownloadListener listener2 = new DownloadListener2();
DownloadListener combinedListener = new DownloadListenerBunch.Builder()
.append(listener1)
.append(listener2)
.build();
DownloadTask task = new DownloadTask.build(url, file).build();
task.enqueue(combinedListener);
为多个任务动态设置监听:
UnifiedListenerManager manager = new UnifiedListenerManager();
DownloadListener listener1 = new DownloadListener1();
DownloadListener listener2 = new DownloadListener2();
DownloadListener listener3 = new DownloadListener3();
DownloadListener listener4 = new DownloadListener4();
DownloadTask task = new DownloadTask.build(url, file).build();
manager.attachListener(task, listener1);
manager.attachListener(task, listener2);
manager.detachListener(task, listener2);
// 当一个任务结束时,这个任务的所有监听器都被移除
manager.addAutoRemoveListenersWhenTaskEnd(task.getId());
// enqueue task to start.
manager.enqueueTaskWithUnifiedListener(task, listener3);
manager.attachListener(task, listener4);
下面我们来分析一下这个下载框架的源码:
OkDownload
首先看一下OkDownload这个类,这个类定义了所有的下载策略,我们可以自定义一些下载策略,可以通过OkDownload的Builder构造自定义的一个OkDownload实例,再通过OkDownload.setSingletonInstance进行设置:
OkDownload.Builder builder = new OkDownload.Builder(context)
.downloadStore(downloadStore) //断点信息存储的位置,默认是SQLite数据库
.callbackDispatcher(callbackDispatcher) //监听回调分发器,默认在主线程回调
.downloadDispatcher(downloadDispatcher) //下载管理机制,最大下载任务数、同步异步执行下载任务的处理
.connectionFactory(connectionFactory) //选择网络请求框架,默认是OkHttp
.outputStreamFactory(outputStreamFactory) //构建文件输出流DownloadOutputStream,是否支持随机位置写入
.downloadStrategy(downloadStrategy) //下载策略,文件分为几个线程下载
.processFileStrategy(processFileStrategy) //多文件写文件的方式,默认是根据每个线程写文件的不同位置,支持同时写入。
.monitor(monitor); //下载状态监听
OkDownload.setSingletonInstance(builder.build());
DownloadTask
DownloadTask下载任务类,可通过它的Builder来构造一个下载任务,我们看它是如何执行的:
public void execute(DownloadListener listener) {
this.listener = listener;
OkDownload.with().downloadDispatcher().execute(this);
}
public void enqueue(DownloadListener listener) {
this.listener = listener;
OkDownload.with().downloadDispatcher().enqueue(this);
}
可以看到都是通过downloadDispatcher来执行下载任务的,默认的downloadDispatcher是一个DownloadDispatcher实例,我们以同步执行一个下载任务为例,看它是如何下载的:
public void execute(DownloadTask task) {
Util.d(TAG, "execute: " + task);
final DownloadCall call;
synchronized (this) {
if (inspectCompleted(task)) return;
if (inspectForConflict(task)) return;
call = DownloadCall.create(task, false, store);
runningSyncCalls.add(call);
}
syncRunCall(call);
}
void syncRunCall(DownloadCall call) {
ca