使用FileDownLoader下载文件

    xiaoxiao2021-03-25  188

    关于FileDownLoader这个下载引擎在这里我就不多做介绍了,具体可以打开github上的地址:FileDownLoader 查看~

    博客结尾处也有简略说明

    使用FileDownLoader

    第一步:如果使用的是AndroidStudio开发工具,需要在项目中引用:

    compile 'com.liulishuo.filedownloader:library:1.3.0'   第二步:然后在Application.Oncreate  中进行全局初始化 public XXApplication extends Application{       ...       @Override       public void onCreate() {           /**           * 仅仅是缓存Application的Context,不耗时           */           FileDownloader.init(getApplicationContext);       }       ...   }  

    启动单任务下载

    FileDownloader.getImpl().create(url) .setPath(path) .setListener(new FileDownloadListener() { @Override protected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) { } @Override protected void connected(BaseDownloadTask task, String etag, boolean isContinue, int soFarBytes, int totalBytes) { } @Override protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) { } @Override protected void blockComplete(BaseDownloadTask task) { } @Override protected void retry(final BaseDownloadTask task, final Throwable ex, final int retryingTimes, final int soFarBytes) { } @Override protected void completed(BaseDownloadTask task) { } @Override protected void paused(BaseDownloadTask task, int soFarBytes, int totalBytes) { } @Override protected void error(BaseDownloadTask task, Throwable e) { } @Override protected void warn(BaseDownloadTask task) { } }).start();

    下载介绍一下我写的单例下载:

    1.单任务下载

    <span style="font-size:14px;">package com.kuaibao.skuaidi.manager;         import com.liulishuo.filedownloader.BaseDownloadTask;   import com.liulishuo.filedownloader.FileDownloadListener;   import com.liulishuo.filedownloader.FileDownloader;      /**   * Created by gudd   * on 2016/10/27.   * compile 'com.liulishuo.filedownloader:library:1.3.0'     */      public class FileDownloaderManager {       public static FileDownloaderManager instance = null;          private FileDownloaderManager() {       }// 避免类在外部被实例化          public static FileDownloaderManager getInstance() {           if (null == instance) {               instance = new FileDownloaderManager();           }           return instance;       }          /**       * 单任务下载       *       * @param downLoadUri  文件下载网络地址       * @param destinationUri 下载文件的存储绝对路径       */       public void startDownLoadFileSingle(String downLoadUri, String destinationUri,FileDownLoaderCallBack callBack) {           FileDownloader.getImpl().create(downLoadUri).setPath(destinationUri).setListener(fileDownloadListener(callBack)).start();       }      // 下载方法       private FileDownloadListener fileDownloadListener(final FileDownLoaderCallBack callBack) {           return new FileDownloadListener() {               @Override               protected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) {                   //等待,已经进入下载队列               }                  @Override               protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) {                   //下载进度回调                   if (callBack != null){                       callBack.downLoadProgress(task,soFarBytes,totalBytes);                   }               }                  @Override               protected void completed(BaseDownloadTask task) {                   //完成整个下载过程                   if (callBack != null){                       callBack.downLoadComplated(task);                   }               }                  @Override               protected void paused(BaseDownloadTask task, int soFarBytes, int totalBytes) {                   //暂停下载               }                  @Override               protected void error(BaseDownloadTask task, Throwable e) {                   //下载出现错误                   if (callBack != null){                       callBack.downLoadError(task,e);                   }               }                  @Override               protected void warn(BaseDownloadTask task) {                   //在下载队列中(正在等待/正在下载)已经存在相同下载连接与相同存储路径的任务               }           };       }       // 这里是下载过程中的回调,由于下载过程中,我们只需要知道文件是否下载完成、文件是否下载失败、还有文件下载进度,</span> 

    所以这里只自定义三个方法用于回调  

    <span style="font-size:14px;">     public interface FileDownLoaderCallBack{           void downLoadComplated(BaseDownloadTask task);           void downLoadError(BaseDownloadTask task, Throwable e);           void downLoadProgress(BaseDownloadTask task, int soFarBytes, int totalBytes);       }         }</span> 

    所以,你在使用的时候只需要使用一行代码就可以下载文件了:

    [java]  view plain  copy   FileDownloaderManager.getInstance().startDownLoadFileSingle("下载地址",“保存地址”,new FileDownLoaderCallBack({   ......   }));  

    启动多任务下载

    final FileDownloadListener queueTarget = new FileDownloadListener() { @Override protected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) { } @Override protected void connected(BaseDownloadTask task, String etag, boolean isContinue, int soFarBytes, int totalBytes) { } @Override protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) { } @Override protected void blockComplete(BaseDownloadTask task) { } @Override protected void retry(final BaseDownloadTask task, final Throwable ex, final int retryingTimes, final int soFarBytes) { } @Override protected void completed(BaseDownloadTask task) { } @Override protected void paused(BaseDownloadTask task, int soFarBytes, int totalBytes) { } @Override protected void error(BaseDownloadTask task, Throwable e) { } @Override protected void warn(BaseDownloadTask task) { } }; // 第一种方式 : //for (String url : URLS) { // FileDownloader.getImpl().create(url) // .setCallbackProgressTimes(0) // 由于是队列任务, 这里是我们假设了现在不需要每个任务都回调`FileDownloadListener#progress`, 我们只关系每个任务是否完成, 所以这里这样设置可以很有效的减少ipc. // .setListener(queueTarget) // .asInQueueTask() // .enqueue(); //} //if(serial){ // 串行执行该队列 // FileDownloader.getImpl().start(queueTarget, true); // } // if(parallel){ // 并行执行该队列 // FileDownloader.getImpl().start(queueTarget, false); //} // 第二种方式: final FileDownloadQueueSet queueSet = new FileDownloadQueueSet(downloadListener); final List<BaseDownloadTask> tasks = new ArrayList<>(); for (int i = 0; i < count; i++) { tasks.add(FileDownloader.getImpl().create(Constant.URLS[i]).setTag(i + 1)); } queueSet.disableCallbackProgressTimes(); // 由于是队列任务, 这里是我们假设了现在不需要每个任务都回调`FileDownloadListener#progress`, 我们只关系每个任务是否完成, 所以这里这样设置可以很有效的减少ipc. // 所有任务在下载失败的时候都自动重试一次 queueSet.setAutoRetryTimes(1); if (serial) { // 串行执行该任务队列 queueSet.downloadSequentially(tasks); // 如果你的任务不是一个List,可以考虑使用下面的方式,可读性更强 // queueSet.downloadSequentially( // FileDownloader.getImpl().create(url).setPath(...), // FileDownloader.getImpl().create(url).addHeader(...,...), // FileDownloader.getImpl().create(url).setPath(...) // ); } if (parallel) { // 并行执行该任务队列 queueSet.downloadTogether(tasks); // 如果你的任务不是一个List,可以考虑使用下面的方式,可读性更强 // queueSet.downloadTogether( // FileDownloader.getImpl().create(url).setPath(...), // FileDownloader.getImpl().create(url).setPath(...), // FileDownloader.getImpl().create(url).setSyncCallback(true) // ); } // 串行任务动态管理也可以使用FileDownloadSerialQueue。

    全局接口说明(FileDownloader)

    所有的暂停,就是停止,会释放所有资源并且停到所有相关线程,下次启动的时候默认会断点续传

    方法名备注init(Context)缓存Context,不会启动下载进程init(Context, InitCustomMaker)缓存Context,不会启动下载进程;在下载进程启动的时候,会传入定制化组件create(url:String)创建一个下载任务start(listener:FileDownloadListener, isSerial:boolean)启动是相同监听器的任务,串行/并行启动pause(listener:FileDownloadListener)暂停启动相同监听器的任务pauseAll(void)暂停所有任务pause(downloadId)暂停downloadId的任务clear(downloadId, targetFilePath)强制清理ID为downloadId的任务在filedownloader中的数据getSoFar(downloadId)获得下载Id为downloadId的soFarBytesgetTotal(downloadId)获得下载Id为downloadId的totalBytesbindService(void)主动启动下载进程(可事先调用该方法(可以不调用),保证第一次下载的时候没有启动进程的速度消耗)unBindService(void)主动关停下载进程unBindServiceIfIdle(void)如果目前下载进程没有任务正在执行,则关停下载进程isServiceConnected(void)是否已经启动并且连接上下载进程(可参考任务管理demo中的使用)getStatusIgnoreCompleted(downloadId)获取不包含已完成状态的下载状态(如果任务已经下载完成,将收到INVALID)getStatus(id:int, path:String)获取下载状态getStatus(url:String, path:String)获取下载状态setGlobalPost2UIInterval(intervalMillisecond:int)为了避免掉帧,这里是设置了最多每interval毫秒抛一个消息到ui线程(使用Handler),防止由于回调的过于频繁导致ui线程被ddos导致掉帧。 默认值: 10ms. 如果设置小于0,将会失效,也就是说每个回调都直接抛一个消息到ui线程setGlobalHandleSubPackageSize(packageSize:int)为了避免掉帧, 如果上面的方法设置的间隔是一个小于0的数,这个packageSize将不会生效。packageSize这个值是为了避免在ui线程中一次处理过多回调,结合上面的间隔,就是每个interval毫秒间隔抛一个消息到ui线程,而每个消息在ui线程中处理packageSize个回调。默认值: 5enableAvoidDropFrame(void)开启 避免掉帧处理。就是将抛消息到ui线程的间隔设为默认值10ms, 很明显会影响的是回调不会立马通知到监听器(FileDownloadListener)中,默认值是: 最多10ms处理5个回调到监听器中disableAvoidDropFrame(void)关闭 避免掉帧处理。就是将抛消息到ui线程的间隔设置-1(无效值),这个就是让每个回调都会抛一个消息ui线程中,可能引起掉帧isEnabledAvoidDropFrame(void)是否开启了 避免掉帧处理。默认是开启的startForeground(id:int, notification:Notification)设置FileDownloadService为前台模式,保证用户从最近应用列表移除应用以后下载服务不会被杀stopForeground(removeNotification:boolean)取消FileDownloadService的前台模式setTaskCompleted(url:String, path:String, totalBytes:long)用于告诉FileDownloader引擎,以指定Url与Path的任务已经通过其他方式(非FileDownloader)下载完成setTaskCompleted(taskAtomList:List)用于告诉FileDownloader引擎,指定的一系列的任务都已经通过其他方式(非FileDownloader)下载完成setMaxNetworkThreadCount(int)设置最大并行下载的数目(网络下载线程数), [1,12]clearAllTaskData()清空filedownloader数据库中的所有数据

    定制化组件接口说明(InitCustomMaker)

    方法名需实现接口已有组件默认组件说明databaseFileDownloadDatabaseDefaultDatabaseImplDefaultDatabaseImpl传入定制化数据库组件,用于存储用于断点续传的数据okHttpClientokHttpClientokHttpClientokHttpClient传入定制化的okHttpClient,用于下载时使用outputStreamCreatorFileDownloadOutputStreamFileDownloadRandomAccessFile、FileDownloadBufferedOutputStream、FileDownloadOkioFileDownloadRandomAccessFile传入输出流组件,用于下载时写文件使用maxNetworkThreadCount--3传入创建下载引擎时,指定可用的下载线程个数

    Task接口说明

    方法名备注setPath(path:String)下载文件的存储绝对路径setPath(path:String, pathAsDirectory:boolean)如果pathAsDirectory是true,path就是存储下载文件的文件目录(而不是路径),此时默认情况下文件名filename将会默认从response#header中的contentDisposition中获得setListener(listener:FileDownloadListener)设置监听,可以以相同监听组成队列setCallbackProgressTimes(times:int)设置整个下载过程中FileDownloadListener#progress最大回调次数setCallbackProgressIgnored()忽略所有的FileDownloadListener#progress的回调setCallbackProgressMinInterval(minIntervalMillis:int)设置每个FileDownloadListener#progress之间回调间隔(ms)setTag(tag:Object)内部不会使用,在回调的时候用户自己使用setTag(key:int, tag:Object)用于存储任意的变量方便回调中使用,以key作为索引setForceReDownload(isForceReDownload:boolean)强制重新下载,将会忽略检测文件是否健在setFinishListener(listener:FinishListener)结束监听,仅包含结束(over(void))的监听setAutoRetryTimes(autoRetryTimes:int)当请求或下载或写文件过程中存在错误时,自动重试次数,默认为0次setSyncCallback(syncCallback:boolean)如果设为true, 所有FileDownloadListener中的回调都会直接在下载线程中回调而不抛到ui线程, 默认为falseaddHeader(name:String, value:String)添加自定义的请求头参数,需要注意的是内部为了断点续传,在判断断点续传有效时会自动添加上(If-Match与Range参数),请勿重复添加导致400或其他错误addHeader(line:String)添加自定义的请求头参数,需要注意的是内部为了断点续传,在判断断点续传有效时会自动添加上(If-Match与Range参数),请勿重复添加导致400或其他错误setMinIntervalUpdateSpeed(minIntervalUpdateSpeedMs:int)设置下载中刷新下载速度的最小间隔removeAllHeaders(name:String)删除由自定义添加上去请求参数为{name}的所有键对setWifiRequired(isWifiRequired:boolean)设置任务是否只允许在Wifi网络环境下进行下载。 默认值falseasInQueueTask(void):InQueueTask申明该任务将会是队列任务中的一个任务,并且转化为InQueueTask,之后可以调用InQueueTask#enqueue将该任务入队以便于接下来启动队列任务时,可以将该任务收编到队列中start(void)启动孤立的下载任务pause(void)暂停下载任务(也可以理解为停止下载,但是在start的时候默认会断点续传)getId(void):int获取唯一Id(内部通过url与path生成)getUrl(void):String获取下载连接getCallbackProgressTimes(void):int获得progress最大回调次数getCallbackProgressMinInterval(void):int获得每个progress之间的回调间隔(ms)getPath(void):String获取文件路径 或 文件目录isPathAsDirectory判断getPath()返回的路径是文件存储目录(directory),还是文件存储路径(directory/filename)getTargetFilePath获取目标文件的存储路径getListener(void):FileDownloadListener获取监听器getSoFarBytes(void):int获取已经下载的字节数getTotalBytes(void):int获取下载文件总大小getStatus(void):int获取当前的状态isForceReDownload(void):boolean是否强制重新下载getEx(void):Throwable获取下载过程抛出的ThrowableisReusedOldFile(void):boolean判断是否是直接使用了旧文件(检测是有效文件),没有启动下载getTag(void):Object获取用户setTag进来的ObjectgetTag(key:int):Object根据key获取存储在task中的变量isContinue(void):boolean是否成功断点续传getEtag(void):String获取当前下载获取到的ETaggetAutoRetryTimes(void):int自动重试次数getRetryingTimes(void):int当前重试次数。将要开始重试的时候,会将接下来是第几次isSyncCallback(void):boolean是否是设置了所有FileDownloadListener中的回调都直接在下载线程直接回调而不抛到ui线程getSpeed():int获取任务的下载速度, 下载过程中为实时速度,下载结束状态为平均速度isUsing():boolean判断当前的Task对象是否在引擎中启动过isWifiRequired():boolean获取当前任务是否被设置过只允许在Wifi网络环境下下载

    监听器(FileDownloadListener)说明

    一般的下载回调流程:
    pending -> started -> connected -> (progress <->progress) -> blockComplete -> completed
    可能会遇到以下回调而直接终止整个下载过程:
    paused / completed / error / warn
    如果检测存在已经下载完成的文件(可以通过isReusedOldFile进行决策是否是该情况)(也可以通过setForceReDownload(true)来避免该情况):
    blockComplete -> completed
    方法说明
    回调方法备注带回数据pending等待,已经进入下载队列数据库中的soFarBytes与totalBytesstarted结束了pending,并且开始当前任务的Runnable-connected已经连接上ETag, 是否断点续传, soFarBytes, totalBytesprogress下载进度回调soFarBytesblockComplete在完成前同步调用该方法,此时已经下载完成-retry重试之前把将要重试是第几次回调回来之所以重试遇到Throwable, 将要重试是第几次, soFarBytescompleted完成整个下载过程-paused暂停下载soFarByteserror下载出现错误抛出的Throwablewarn在下载队列中(正在等待/正在下载)已经存在相同下载连接与相同存储路径的任务-

    由于FileDownloadListener中的方法回调过快,导致掉帧?

    你有两种方法可以解决这个问题

    FileDownloader#enableAvoidDropFrame, 默认 就是开启的BaseDownloadTask#setSyncCallback, 默认是false, 如果设置为true,所有的回调都会在下载线程直接同步调用而不会抛到ui线程。

    FileDownloadMonitor

    你可以添加一个全局监听器来进行打点或者是调试

    方法名备注setGlobalMonitor(monitor:IMonitor)设置与替换一个全局监听器到下载引擎中releaseGlobalMonitor(void)释放已经设置到下载引擎中的全局监听器getMonitor(void)获取已经设置到下载引擎中的全局监听器
    FileDownloadMonitor.IMonitor

    监听器接口类

    接口备注onRequestStart(count:int, serial:boolean, lis:FileDownloadListener)将会在启动队列任务是回调这个方法onRequestStart(task:BaseDownloadTask)将会在启动单一任务时回调这个方法onTaskBegin(task:BaseDownloadTask)将会在内部接收并开始task的时候回调这个方法(会在pending回调之前)onTaskStarted(task:BaseDownloadTask)将会在task结束pending开始task的runnable的时候回调该方法onTaskOver(task:BaseDownloadTask)将会在task走完所有生命周期是回调这个方法

    FileDownloadUtils

    方法名备注setDefaultSaveRootPath(path:String)在整个引擎中没有设置路径时BaseDownloadTask#setPath这个路径将会作为它的Root pathgetTempPath获取用于存储还未下载完成文件的临时存储路径: filename.tempisFilenameConverted(context:Context)判断是否所有数据库中下载中的任务的文件名都已经从filename(在旧架构中)转为filename.temp

    FileDownloadNotificationHelper

    如何快速集成Notification呢? 建议参考NotificationMinSetActivity、NotificationSampleActivity。

    filedownloader.properties

    如果你需要定制化FileDownloader,可以在你的项目模块的assets 目录下添加 'filedownloader.properties' 文件(如/demo/src/main/assets/filedownloader.properties),然后添加以下可选相关配置。

    格式: keyword=value

    关键字描述默认值http.lenient如果你遇到了: 'can't know the size of the download file, and its Transfer-Encoding is not Chunked either', 但是你想要忽略类似的返回头不规范的错误,直接将该关键字参数设置为true即可,我们将会将其作为chunck进行处理falseprocess.non-separateFileDownloadService 默认是运行在独立进程':filedownloader'上的, 如果你想要FileDownloadService共享并运行在主进程上, 将该关键字参数设置为true,可以有效减少IPC产生的I/Ofalsedownload.min-progress-step最小缓冲大小,用于判定是否是时候将缓冲区中进度同步到数据库,以及是否是时候要确保下缓存区的数据都已经写文件。值越小,更新会越频繁,下载速度会越慢,但是应对进程被无法预料的情况杀死时会更加安全65536download.min-progress-time最小缓冲时间,用于判定是否是时候将缓冲区中进度同步到数据库,以及是否是时候要确保下缓存区的数据都已经写文件。值越小,更新会越频繁,下载速度会越慢,但是应对进程被无法预料的情况杀死时会更加安全2000download.max-network-thread-count用于同时下载的最大网络线程数, 区间[1, 12]3file.non-pre-allocation是否不需要在开始下载的时候,预申请整个文件的大小(content-length)false

    III. 异常处理

    所有的异常,都将在 FileDownloadListener#error(BaseDownloadTask, Throwable) 中获知。

    Exception原因FileDownloadHttpException在发出请求以后,response-code不是200(HTTP_OK),也不是206(HTTP_PARTIAL)的情况下会抛出该异常; 在这个异常对象会带上 response-code、response-header、request-header。FileDownloadGiveUpRetryException在请求返回的 response-header 中没有带有文件大小(content-length),并且不是流媒体(transfer-encoding)的情况下会抛出该异常;出现这个异常,将会忽略所有重试的机会(BaseDownloadTask#setAutoRetryTimes). 你可以通过在filedownloader.properties中添加 http.lenient=true 来忽略这个异常,并且在该情况下,直接作为流媒体进行下载。FileDownloadOutOfSpaceException当将要下载的文件大小大于剩余磁盘大小时,会抛出这个异常。其他程序错误。

    III. 低内存情况

    非下载进程(一般是UI进程):

    这边的数据并不多,只是一些队列数据,用不了多少内存。

    前台进程数据被回收:

    如果在前台的时候这个数据都被回收了, 你的应用应该也挂了。极低概率事件。

    后台进程数据被回收:

    一般事件, 如果是你的下载是UI进程启动的,如果你的UI进程处于后台进程(可以理解为应用被退到后台)状态,在内存不足的情况下会被回收(回收优先级高于服务进程),此时分两种情况:

    是串行队列任务,在回收掉UI进程内存以后,下载进程会继续下载完已经pending到下载进程的那个任务,而还未pending到下载进程的任务会中断下载(由于任务驱动线性执行的是在UI进程); 有损体验: 下次进入应用重启启动整个队列,会继续上次的下载。

    是并行队列任务,在回收掉UI进程内存以后,下载进程会继续下载所有任务(所有已经pending到下载进程的任务,由于这里的pending速度是很快的,因此几乎是点击并行下载,所有任务在很短的时间内都已经pending到下载进程了),而UI进程由于被回收,将不会收到所有的监听; 有损体验: 下次进入应用重新启动整个队列,就会和正常的下载启动一致,收到所有情况的监听。

    下载进程:

    对内存有一定的占用,但是并不多,每次启动进程会根据数据的有效性进行清理冗余数据,被回收是低概率事件

    由于下载不断有不同的buffer占用内存,但是由于在下载时,是活跃的服务进程,因此被回收是低概率事件(会先回收完所有空进程、后台进程(后台应用)以后,如果内存还不够,才会回收该进程)。

    即使被回收,也不会有任何问题。由于我们使用的是START_STICKY(如果不希望被重启可主动调用FileDownloader#unBindService/FileDownloader#unBindServiceIfIdle),因此在内存足够的时候,下载进程会尝试重启(系统调度),非下载进程(一般是UI进程) 接收到下载进程的连接,会继续下载与继续接收回调,下载进程也会断点续传没有下载完的所有任务(无论并行与串行),不会影响体验。

    IV. LICENSE

    Copyright (c) 2015 LingoChamp Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 来源: <https://github.com/lingochamp/FileDownloader/blob/master/README-zh.md#filedownloader>
    转载请注明原文地址: https://ju.6miu.com/read-4812.html

    最新回复(0)