美文网首页
okdownloader源码分析

okdownloader源码分析

作者: xinayida | 来源:发表于2018-01-04 13:19 被阅读0次

    作者是流利说的Android架构负责人,本来有一个5k+ star的FileDownloader项目,但是又重新写了这个下载框架okdownloader,具体原因如下:

    • FileDownloader framework is not easy to write unit-test, it is not a testable framework, so it is not stable enough.
    • The core library of FileDownloader is too complex and not pure enough, so 5K+ star 1K+ fork with around 10 PR

    相对于FileDownloader的优势

    • 单元测试覆盖度非常高
    • 更简单的接口
    • 支持任务优先级
    • 使用Uri标识文件来存储output-stream
    • 核心代码更加轻量及纯净
    • 更灵活的回调、监听机制
    • 更容易扩展
    • 保持性能的基础上减少线程数量
    • 文件IO线程池独立于网络IO线程池
    • response header中不包含文件名时,自动从URL中获取(使用正则表达式实现)

    主框架分析

    • 下载请求通过DownloadTask.Builder封装,通过各种set方法配置请求参数

    • 全部下载策略定义在OkDownload中,如果需要自定义则需要通过内置的Builder构造出一个实例,再通过setSingletonInstance方法设置,替换默认实现

    • 下载请求过程分为两个调用连(connect、fetch),在DownloadChain中分别通过#processConnect以及#processFetch的递归调用来实现

    • 下载文件的分块逻辑实现在BreakpointInterceptor中,当DownloadCall创建新task时,首先将一个空的BlockInfo添加到BreakpointInfo#blockInfoList中并启动对应的DownloadChain,同时park当前线程直到第一个DownloadChain中的BreakpointInterceptor计算好分块数量,之后清空BreakpointInfo#blockInfoList并unpark当前线程,执行后续操作


      下载流程.png
    • 多种下载回调,根据需求来选择DownloadListener1,DownloadListener2,etc..

    • 多任务下载,使用DownloadContext来构造

    • cancel操作不会删除已下载的文件,只相当与暂停,重新下载时会从断点继续下载

        //DownloadCall#execute 任务开始
        void taskStart(DownloadTask task);
        //DownloadCall#execute 从头开始
        void downloadFromBeginning(DownloadTask task, BreakpointInfo info, ResumeFailedCause cause);
        //DownloadCall#execute 从断点开始
        void downloadFromBreakpoint(DownloadTask task, BreakpointInfo info);
        //HeaderInterceptor#interceptConnect 创建链接开始
        void connectStart(DownloadTask task, int blockIndex,
                          @NonNull Map<String, List<String>> requestHeaderFields);
        //HeaderInterceptor#interceptConnect 创建链接结束
        void connectEnd(DownloadTask task, int blockIndex, int responseCode,
                        @NonNull Map<String, List<String>> responseHeaderFields);
        //BreakpointInterceptor#interceptConnect 分块结束
        void splitBlockEnd(DownloadTask task, BreakpointInfo info);
        //DownloadChain#start 开始下载
        void fetchStart(DownloadTask task, int blockIndex, long contentLength);
        //FetchDataInterceptor#interceptFetch->DownloadChain#flushNoCallbackIncreaseBytes 下载进度
        void fetchProgress(DownloadTask task, int blockIndex, long increaseBytes);
        //DownloadChain#start 下载结束
        void fetchEnd(DownloadTask task, int blockIndex, long contentLength);
        //DownloadCall#execute 任务结束
        void taskEnd(DownloadTask task, EndCause cause, @Nullable Exception realCause);
    

    代码结构

    .
    ├── DownloadContext.java //多个下载任务串/并行下载,使用QueueSet来做设置
    ├── DownloadListener.java //下载状态回调接口定义
    ├── DownloadMonitor.java
    ├── DownloadSerialQueue.java
    ├── DownloadTask.java //单个下载任务
    ├── OkDownload.java //入口类,负责下载任务装配
    ├── OkDownloadProvider.java //单纯为了获取上下文Context
    ├── SpeedCalculator.java //下载速度计算
    ├── StatusUtil.java //获取DownloadTask下载状态,检查下载文件是否已经下载完成等
    ├── UnifiedListenerManager.java //多个listener管理
    └── core
    ├── NamedRunnable.java //可命名的线程实现
    ├── Util.java //工具类
    ├── breakpoint
    │ ├── BlockInfo.java //下载分块信息,记录当前块的下载进度,第0个记录整个下载任务的进度
    │ ├── BreakpointInfo.java // BlockInfo聚合类,包含文件名、URL等信息
    │ ├── BreakpointStore.java //下载过程中断点信息存储接口定义
    │ └── BreakpointStoreOnCache.java //断点信息存储在缓存中的实现
    ├── cause
    │ ├── EndCause.java //结束状态
    │ └── ResumeFailedCause.java //下载异常原因
    ├── connection
    │ ├── DownloadConnection.java // 下载链接接口定义
    │ └── DownloadUrlConnection.java //下载链接UrlConnection实现
    ├── dispatcher
    │ ├── CallbackDispatcher.java //DownloadListener分发代理(是否回调到UI线程,默认为true)
    │ └── DownloadDispatcher.java //下载任务线程分配
    ├── download
    │ ├── DownloadCache.java //MultiPointOutputStream包裹类
    │ ├── DownloadCall.java //下载任务线程,包含DownloadTask、DownloadChain的list以及DownloadCache
    │ ├── DownloadChain.java //持有DownloadTask、BreakpointInfo、DownloadCache、DownloadConnection等对象,链式调用各connect及fetch的Interceptor,开启下载任务
    │ └── DownloadStrategy.java //下载策略,包括分包策略、下载文件命名策略以及response是否可用
    ├── exception //各种异常
    │ ├── FileBusyAfterRunException.java
    │ ├── InterruptException.java
    │ ├── PreAllocateException.java
    │ ├── ResumeFailedException.java
    │ ├── RetryException.java
    │ └── ServerCancelledException.java
    ├── file
    │ ├── DownloadOutputStream.java //输出流接口定义
    │ ├── DownloadUriOutputStream.java //Uri输出流实现
    │ ├── MultiPointOutputStream.java //多block输出流管理
    │ └── ProcessFileStrategy.java //下载过程中文件处理逻辑
    ├── interceptor
    │ ├── BreakpointInterceptor.java //connect时分块,fetch时循环调用FetchDataInterceptor获取数据
    │ ├── FetchDataInterceptor.java //fetch时读写流数据,记录增加bytes长度
    │ ├── Interceptor.java
    │ ├── RetryInterceptor.java //错误处理、connect时重试机制,fetch结束时同步输出流,确保写入数据完整
    │ └── connect
    │ ├── CallServerInterceptor.java //启动DownloadConnection
    │ ├── HeaderInterceptor.java //添加头信息,调用connectStart、connectEnd
    │ └── RedirectInterceptor.java //重定向相关处理
    └── listener //多种回调及辅助接口
    ├── DownloadListener1.java
    ├── DownloadListener2.java
    ├── DownloadListener3.java
    ├── DownloadListener4.java
    ├── DownloadListener4WithSpeed.java
    └── assist
    ├── Listener1Assist.java
    ├── Listener4Assist.java
    └── Listener4SpeedAssistExtend.java

    相关文章

      网友评论

          本文标题:okdownloader源码分析

          本文链接:https://www.haomeiwen.com/subject/dlhlnxtx.html