RxJava2和Retrofit2用的越來越多,最近也在封裝一個通用的網(wǎng)絡請求庫,其中就包括了單文件下載的方法,所以這里進行記錄。文末附帶Demo
由于網(wǎng)上很多的方法都是使用攔截器進行進度的監(jiān)聽,個人覺得使用起來非常復雜和,所以取了個巧,在文件寫入到硬盤的時候對文件讀寫進行監(jiān)聽,就解決了retrofit2下載文件沒有進度監(jiān)聽的問題。
先上封裝之后的使用代碼,使用簡單,直接回調下載之后的文件

圖1
封裝步驟
- 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);
}
//可以重寫,具體可由子類實現(xiàn)
@Override
public void onComplete() {
}
//下載成功的回調
public abstract void onDownLoadSuccess(T t);
//下載失敗回調
public abstract void onDownLoadFail(Throwable throwable);
//下載進度監(jiān)聽
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;
//這里就是對進度的監(jiān)聽回調
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 監(jiān)聽回調
*/
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文件夾下的方法