Android 文件下载引擎,稳定、高效、灵活、简单易用。
GitHub 地址:FileDownloader
效果图:
- 简单易用
- 单任务多线程/多连接/分块下载(并支持通过ConnectionCountAdapter定制)
- 高并发
- 灵活
- 可选择性支持: 独立/非独立进程
- 自动断点续传
需要注意
-
为了绝大多数使用性能考虑,目前下载引擎目前受限于int可表示的范围,而我们的回调total与so far以byte为单位回调,因此最大只能表示到2^31-1=2_147_483_647 = 1.99GB(ps: 如果有更大的文件下载需求,提issue,我们会进行一些巧妙的优化,利用负值区间?根据大小走特殊通道传输?)
-
暂停: paused, 恢复: 直接调用start,默认就是断点续传
1. 在项目中引用
implementation 'com.liulishuo.filedownloader:library:1.7.7'
2. 全局初始化
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Log.d("feifei","MyApplication.onCreate()");
FileDownloader.setupOnApplicationOnCreate(this)
.connectionCreator(new FileDownloadUrlConnection
.Creator(new FileDownloadUrlConnection.Configuration()
.connectTimeout(15_000) // set connection timeout.
.readTimeout(15_000) // set read timeout.
))
.commit();
}
}
3. 单任务下载
BaseDownloadTask singleTask ;
public int singleTaskId = 0;
String apkUrl = "http://cdn.llsapp.com/android/LLS-v4.0-595-20160908-143200.apk";
String singleFileSaveName = "liulishuo.apk";
public String mSinglePath = FileDownloadUtils.getDefaultSaveRootPath()+ File.separator+"feifei_save"
+File.separator+singleFileSaveName;;
public String mSaveFolder = FileDownloadUtils.getDefaultSaveRootPath()+File.separator+"feifei_save";
public void start_single(){
String url = apkUrl;
singleTask = FileDownloader.getImpl().create(url)
// .setPath(mSinglePath,false)
.setPath(mSinglePath,true)
.setCallbackProgressTimes(300)
.setMinIntervalUpdateSpeed(400)
//.setTag()
.setListener(new FileDownloadSampleListener(){
@Override
protected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) {
Log.d("feifei","pending taskId:"+task.getId()+",soFarBytes:"+soFarBytes+",totalBytes:"+totalBytes+",percent:"+soFarBytes*1.0/totalBytes);
}
@Override
protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) {
Log.d("feifei","progress taskId:"+task.getId()+",soFarBytes:"+soFarBytes+",totalBytes:"+totalBytes+",percent:"+soFarBytes*1.0/totalBytes+",speed:"+task.getSpeed());
}
@Override
protected void blockComplete(BaseDownloadTask task) {
Log.d("feifei","blockComplete taskId:"+task.getId()+",filePath:"+task.getPath()+",fileName:"+task.getFilename()+",speed:"+task.getSpeed()+",isReuse:"+task.reuse());
}
@Override
protected void completed(BaseDownloadTask task) {
Log.d("feifei","completed taskId:"+task.getId()+",isReuse:"+task.reuse());
}
@Override
protected void paused(BaseDownloadTask task, int soFarBytes, int totalBytes) {
Log.d("feifei","paused taskId:"+task.getId()+",soFarBytes:"+soFarBytes+",totalBytes:"+totalBytes+",percent:"+soFarBytes*1.0/totalBytes);
}
@Override
protected void error(BaseDownloadTask task, Throwable e) {
Log.d("feifei","error taskId:"+task.getId()+",e:"+e.getLocalizedMessage());
}
@Override
protected void warn(BaseDownloadTask task) {
Log.d("feifei","warn taskId:"+task.getId());
}
});
singleTaskId = singleTask.start();
}
public void pause_single(){
Log.d("feifei","pause_single task:"+singleTaskId);
FileDownloader.getImpl().pause(singleTaskId);
}
public void delete_single(){
//删除单个任务的database记录
boolean deleteData = FileDownloader.getImpl().clear(singleTaskId,mSaveFolder);
File targetFile = new File(mSinglePath);
boolean delate = false;
if(targetFile.exists()){
delate = targetFile.delete();
}
Log.d("feifei","delete_single file,deleteDataBase:"+deleteData+",mSinglePath:"+mSinglePath+",delate:"+delate);
new File(FileDownloadUtils.getTempPath(mSinglePath)).delete();
}
4. 多任务下载
// 多任务下载
private FileDownloadListener downloadListener;
public FileDownloadListener createLis(){
return new FileDownloadSampleListener(){
@Override
protected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) {
if(task.getListener() != downloadListener){
return;
}
Log.d("feifei","pending taskId:"+task.getId()+",fileName:"+task.getFilename()+",soFarBytes:"+soFarBytes+",totalBytes:"+totalBytes+",percent:"+soFarBytes*1.0/totalBytes);
}
@Override
protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) {
if(task.getListener() != downloadListener){
return;
}
Log.d("feifei","progress taskId:"+task.getId()+",fileName:"+task.getFilename()+",soFarBytes:"+soFarBytes+",totalBytes:"+totalBytes+",percent:"+soFarBytes*1.0/totalBytes+",speed:"+task.getSpeed());
}
@Override
protected void blockComplete(BaseDownloadTask task) {
if(task.getListener() != downloadListener){
return;
}
Log.d("feifei","blockComplete taskId:"+task.getId()+",filePath:"+task.getPath()+",fileName:"+task.getFilename()+",speed:"+task.getSpeed()+",isReuse:"+task.reuse());
}
@Override
protected void completed(BaseDownloadTask task) {
if(task.getListener() != downloadListener){
return;
}
Log.d("feifei","completed taskId:"+task.getId()+",isReuse:"+task.reuse());
}
@Override
protected void paused(BaseDownloadTask task, int soFarBytes, int totalBytes) {
if(task.getListener() != downloadListener){
return;
}
Log.d("feifei","paused taskId:"+task.getId()+",soFarBytes:"+soFarBytes+",totalBytes:"+totalBytes+",percent:"+soFarBytes*1.0/totalBytes);
}
@Override
protected void error(BaseDownloadTask task, Throwable e) {
if(task.getListener() != downloadListener){
return;
}
Log.d("feifei","error taskId:"+task.getId()+",e:"+e.getLocalizedMessage());
}
@Override
protected void warn(BaseDownloadTask task) {
if(task.getListener() != downloadListener){
return;
}
Log.d("feifei","warn taskId:"+task.getId());
}
};
}
public void start_multi(){
downloadListener = createLis();
//(1) 创建 FileDownloadQueueSet
final FileDownloadQueueSet queueSet = new FileDownloadQueueSet(downloadListener);
//(2) 创建Task 队列
final List tasks = new ArrayList();
BaseDownloadTask task1 = FileDownloader.getImpl().create(BIG_FILE_URLS[3]).setPath(mSaveFolder,true);
tasks.add(task1);
BaseDownloadTask task2 = FileDownloader.getImpl().create(BIG_FILE_URLS[4]).setPath(mSaveFolder,true);
tasks.add(task2);
//(3) 设置参数
// 每个任务的进度 无回调
//queueSet.disableCallbackProgressTimes();
// do not want each task's download progress's callback,we just consider which task will completed.
queueSet.setCallbackProgressTimes(100);
queueSet.setCallbackProgressMinInterval(100);
//失败 重试次数
queueSet.setAutoRetryTimes(3);
//避免掉帧
FileDownloader.enableAvoidDropFrame();
//(4)串行下载
queueSet.downloadSequentially(tasks);
//(5)任务启动
queueSet.start();
}
public void stop_multi(){
FileDownloader.getImpl().pause(downloadListener);
}
public void deleteAllFile(){
//清除所有的下载任务
FileDownloader.getImpl().clearAllTaskData();
//清除所有下载的文件
int count = 0;
File file = new File(FileDownloadUtils.getDefaultSaveRootPath());
do {
if (!file.exists()) {
break;
}
if (!file.isDirectory()) {
break;
}
File[] files = file.listFiles();
if (files == null) {
break;
}
for (File file1 : files) {
count++;
file1.delete();
}
} while (false);
Toast.makeText(this,
String.format("Complete delete %d files", count), Toast.LENGTH_LONG).show();
}
5. 接口说明
- FileDownloader 中文文档