RxJava2和Retrofit2用的越来越多,最近也在封装一个通用的网络请求库,其中就包括了单文件下载的方法,所以这里进行记录。文末附带Demo
由于网上很多的方法都是使用拦截器进行进度的监听,个人觉得使用起来非常复杂和,所以取了个巧,在文件写入到硬盘的时候对文件读写进行监听,就解决了retrofit2下载文件没有进度监听的问题。
先上封装之后的使用代码,使用简单,直接回调下载之后的文件
封装步骤
- 1.定义接口(使用的时候传入完整的url,@Streaming注解可用于下载大文件)
@Streaming
@GET
Observable<ResponseBody> downLoadFile(@NonNull @Url String url);
- 2.文件下载的回调方法和文件保存方法
public abstract class FileDownLoadObserver<T> extends DefaultObserver<T> {
@Override
public void onNext(T t) {
onDownLoadSuccess(t);
}
@Override
public void onError(Throwable e) {
onDownLoadFail(e);
}
//可以重写,具体可由子类实现
@Override
public void onComplete() {
}
//下载成功的回调
public abstract void onDownLoadSuccess(T t);
//下载失败回调
public abstract void onDownLoadFail(Throwable throwable);
//下载进度监听
public abstract void onProgress(int progress,long total);
/**
* 将文件写入本地
* @param responseBody 请求结果全体
* @param destFileDir 目标文件夹
* @param destFileName 目标文件名
* @return 写入完成的文件
* @throws IOException IO异常
*/
public File saveFile(ResponseBody responseBody, String destFileDir, String destFileName) throws IOException {
InputStream is = null;
byte[] buf = new byte[2048];
int len = 0;
FileOutputStream fos = null;
try {
is = responseBody.byteStream();
final long total = responseBody.contentLength();
long sum = 0;
File dir = new File(destFileDir);
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(dir, destFileName);
fos = new FileOutputStream(file);
while ((len = is.read(buf)) != -1) {
sum += len;
fos.write(buf, 0, len);
final long finalSum = sum;
//这里就是对进度的监听回调
onProgress((int) (finalSum * 100 / total),total);
}
fos.flush();
return file;
} finally {
try {
if (is != null) is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fos != null) fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 3.Retorfit构建
/**
* 下载单文件,该方法不支持断点下载
*
* @param url 文件地址
* @param destDir 存储文件夹
* @param fileName 存储文件名
* @param fileDownLoadObserver 监听回调
*/
public void downloadFile(@NonNull String url, final String destDir, final String fileName, final FileDownLoadObserver<File> fileDownLoadObserver) {
Retrofit retrofit = new Retrofit.Builder()
.client(new OkHttpClient())
.baseUrl(BASE_API.BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
retrofit
.create(BASE_API.class)
.downLoadFile(url)
.subscribeOn(Schedulers.io())//subscribeOn和ObserOn必须在io线程,如果在主线程会出错
.observeOn(Schedulers.io())
.observeOn(Schedulers.computation())//需要
.map(new Function<ResponseBody, File>() {
@Override
public File apply(@NonNull ResponseBody responseBody) throws Exception {
return fileDownLoadObserver.saveFile(responseBody, destDir, fileName);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(fileDownLoadObserver);
}
- 4使用,如一开始的图
downloadFile("文件下载url","目标存储路径","文件名",new FileDownLoadObserver<File>() {
@Override
public void onDownLoadSuccess(File file) {
}
@Override
public void onDownLoadFail(Throwable throwable) {
}
@Override
public void onProgress(int progress,long total) {
}
});
注:github地址的内容包括了文件上传进度封装的方法,具体查看RRMLib文件夹下的方法