Retrofit+okHttp+RxJava打造一款简单易用的Android下载框架


本文介绍自己封装的一套下载框架。

首先要知道,文件下载和我们平时调接口一样,要发起网络请求的,所以我们先找个合适的网络请求库,这里我们选择Retrofit+OkHttp的组合,为了方便支持回调线程切换等功能再加上RxJava的组合。

本框架已更新多次,而本文章可能未及时更新。详细介绍说明请看github
https://github.com/liwuchen/SimpleDownload

一、本框架实现的功能特性

本下载框架实现了这样的特性:

1. 支持断点续传。即下载断开后,支持从已完成的部分开始继续下载。
2. 支持多个任务同时下载。
3. 有各种情况的回调。如下载进度回调,任务取消、完成等回调。
4. 下载任务在子线程进行,回调在主线程。不需要用户自己切换线程。
5. 用户可以自定义文件保存路径和文件名。

二、最终效果图,及使用方法


本框架源码及Demo已上传github,地址:https://github.com/liwuchen/SimpleDownload

如果想在Android Studio项目中使用本框架,可以按如下方式集成:
1.项目根目录下的Build.gradle文件中修改:

allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://www.jitpack.io' } // 添加这行
    }
}

2.模块Build.gradle文件添加:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    api 'com.github.liwuchen:SimpleDownload:1.4.0' 	// 添加这行
}

请使用最新版本。

3.添加权限(读写文件的权限还需动态申请,这里就不贴出了):

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

4.代码中使用起来也很简单:

// 自定义文件夹名
private final String FOLDER_NAME = "SimpleDownload";
// 文件保存路径
private final String SAVE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + FOLDER_NAME;
// 文件下载地址
private final String url = "http://ccr.csslcloud.net/5D2636511DBBCADD/BBD5D1D6504FF2AD9C33DC5901307461/8DE588DAEE2FE914.ccr";
// 保存文件名
private final String fileName = "1.file";
// 定义下载回调
DownloadListener listener = new DownloadListener() {
    @Override
    public void onStartDownload() {}
    
    @Override
    public void onProgress(long downloaded, long total) {}

    @Override
    public void onPauseDownload() {}

    @Override
    public void onCancelDownload() {}

    @Override
    public void onFinishDownload(String savedFile) {}

    @Override
    public void onFail(String errorInfo) {}
};
DownloadManager downloadManager = DownloadManager.getInstance();
// 开始下载
downloadManager.download(url, SAVE_PATH, fileName, listener);
// 暂停下载
downloadManager.pauseDownload(url);
// 继续下载
downloadManager.continueDownload(url);
// 取消下载,不删除文件
downloadManager.cancelDownload(url, false);
// 取消下载,并删除文件
downloadManager.cancelDownload(url, true);

三、关键功能源码说明

本框架的源码类如下:
在这里插入图片描述

1.文件下载和普通网络请求的不同

熟悉Retrofit的同学肯定知道,使用Retrofit发起网络请求,需要编写这样的接口:

@Streaming
@GET
Observable<ResponseBody> rxDownload(@Header("RANGE") String start, @Url String url);

而这里我们加上了@Streaming注解,这表明,请求得到的数据会以流的形式返回,即文件下载。

2. 断点续传如何实现

首先知道,在网络请求时,如果Header加上Range: bytes=xx,则表示从xx个字节开始下载。
那么我们只要继续下载文件时,header里指定开始的位置即可。

本框架里,我们上面贴出的接口里,已含有"RANGE"这个header,使用的时候传入参数即可。

3. 如何得到文件下载进度

本框架使用了自定义拦截器+自定义ResponseBody的方式。
使用拦截器拦截返回的数据,然后将数据转换成自定义ResponseBody。就可以得到下载进度了。

这里要提一下,有的服务器返回数据时,未返回文件的总大小,因此进度回调里返回的总大小是-1,在时用的时候要判断下。

4. 如何把回调切换到主线程

通过RxJava实现,很方便。
如果对RxJava不熟悉的话,可以看我的另一篇关于RxJava的入门讲解:
《RxJava用法入门及操作符讲解,简单易懂》

DownloadService downloadService = retrofit.create(DownloadService.class);
downloadService
    .rxDownload("bytes=" + start + "-", url)
    // 下载过程在IO线程
    .subscribeOn(Schedulers.io())
    // 文件转换为字节流,写入文件,也在IO线程
    .observeOn(Schedulers.io())
    .map(new Function<ResponseBody, InputStream>() {
        @Override
        public InputStream apply(ResponseBody responseBody) throws Exception {
            return responseBody.byteStream();
        }
    })
    .doOnNext(new Consumer<InputStream>() {
        @Override
        public void accept(InputStream inputStream) throws Exception {
        	// 保存文件
            FileUtils.writeFileFromIS(filePath, fileName, inputStream, newFile);
        }
    })
    // 主线程处理回调
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<InputStream>() {
        @Override
        public void onSubscribe(Disposable d) {
            if (listener != null) {
                listener.onStartDownload();
            }
            downloadInfo.setDisposable(d);
        }

        @Override
        public void onNext(InputStream stream) {
        }

        @Override
        public void onError(Throwable e) {
            if (listener != null) {
                listener.onFail(e.getMessage());
                downloadInfo.setState(DownState.ERROR);
            }
        }

        @Override
        public void onComplete() {
            downloadMap.remove(downloadInfo.getUrl());
        }
    });

下面是DownloadProgressListener#progress()方法里监听下载进度及下载完成的回调;

//切换到主线程
Disposable d = Observable.just(1)
	.observeOn(AndroidSchedulers.mainThread())
	.subscribe(new Consumer<Integer>() {
		@Override
		public void accept(Integer integer) {
			if (done) {
				//下载完成
				listener.onFinishDownload(info.getSavePath() + File.separator + info.getFileName());
				info.setState(DownState.FINISH);
			} else {
				//下载进度回调
				if (info.getContentLength() > 0) {
					listener.onProgress(info.getReadLength(), info.getContentLength());
				} else {
					// 获取不到文件总大小(contentLength==0)
					listener.onProgress(info.getReadLength(), -1);
				}
			}
		}
	});

源码已上传:https://github.com/liwuchen/SimpleDownload

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值