基于Ok+Rxjava+retrofit實現(xiàn)斷點續(xù)傳下載
本文為大家分享了實現(xiàn)斷點續(xù)傳下載的具體代碼,供大家參考,具體內(nèi)容如下
1、基于Ok+Rxjava實現(xiàn)斷點續(xù)傳下載
2、基于Ok+Rxjava+Retrofit實現(xiàn)斷點續(xù)傳下載
上一篇博客中介紹了基于Ok+Rxjava實現(xiàn)斷點續(xù)傳下載,這一篇給大家介紹下基于Ok+Rxjava+Retrofit實現(xiàn)斷點續(xù)傳下載,demo下載地址,效果圖跟上一篇圖片一樣,哈哈

說下我的大致思路吧(跟上一篇略有不同):根據(jù)文件下載url按照自己定義的規(guī)則生成文件名,判斷本地同路徑下是否存在此文件,如果存在,文件大小與服務(wù)器上獲取的文件大小一致的情況下,則覆蓋本地文件重新下載;如果文件比服務(wù)器獲取的文件大小小,則執(zhí)行斷點下載,從本地文件長度處開始下載。如果文件不存在,則從0字節(jié)開始下載。
還有的不同是,這里需要重新ResponseBody的source()方法,在這里監(jiān)聽文件下載的進度,然后通過我么自定義的Downloadinterceptor把我們重新的DownloadResponseBody給設(shè)置進去,從而完成我們的進度監(jiān)聽工作。
下面還是上主要代碼:
首先重寫ResponseBody
public class DownloadResponseBody extends ResponseBody {
private ResponseBody responseBody;
//進度回調(diào)接口
private DownFileCallback downFileCallback;
private BufferedSource bufferedSource;
private String downUrl;
public DownloadResponseBody(ResponseBody responseBody, DownFileCallback downFileCallback, String downUrl) {
this.responseBody = responseBody;
this.downFileCallback = downFileCallback;
this.downUrl = downUrl;
}
@Override
public MediaType contentType() {
return responseBody.contentType();
}
@Override
public long contentLength() {
return responseBody.contentLength();
}
@Override
public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
File file = new File(DownloadManager.getInstance().getTemporaryName(downUrl));
@Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
if (null != downFileCallback) {
if (bytesRead != -1) {
long loacalSize = file.length();//本地已下載的長度
long trueTotal = loacalSize + responseBody.contentLength() - totalBytesRead;//文件真實長度
downFileCallback.onProgress(trueTotal,loacalSize);
} else {
}
}
return bytesRead;
}
};
}
}
重寫Interceptor
public class Downloadinterceptor implements Interceptor {
private DownFileCallback downFileCallback;
private String downUrl;
public Downloadinterceptor(DownFileCallback listener,String downUrl) {
this.downFileCallback = listener;
this.downUrl = downUrl;
}
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
return response.newBuilder()
.body(new DownloadResponseBody(response.body(), downFileCallback,downUrl))
.build();
}
}
然后我們的service
public interface HttpService {
/*大文件需要加入Streaming這個判斷,防止下載過程中寫入到內(nèi)存中,造成oom*/
@Streaming
@GET
Observable<ResponseBody> download(@Header("range") String start, @Url String url);
}
接下來我們的DownloadManager中download方法
/**
* 開始下載
* @param url 下載地址
* @param downFileCallback 進度回調(diào)接口
*/
public void download(final String url, final DownFileCallback downFileCallback) {
/*正在下載不處理*/
if (url == null || submap.get(url) != null) {
return;
}
Downloadinterceptor interceptor = new Downloadinterceptor(downFileCallback, url);
okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl("http://imtt.dd.qq.com")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
final HttpService httpservice = retrofit.create(HttpService.class);
ProgressDownSubscriber subscriber =
Observable.just(url)
.flatMap(new Function<String, ObservableSource<DownloadInfo>>() {
@Override
public ObservableSource<DownloadInfo> apply(String s) throws Exception {
return Observable.just(createDownInfo(s));
}
})
.map(new Function<DownloadInfo, DownloadInfo>() {
@Override
public DownloadInfo apply(DownloadInfo s) throws Exception {
return getRealFileName(s);
}
})
.flatMap(new Function<DownloadInfo, Observable<ResponseBody>>() {
@Override
public Observable<ResponseBody> apply(DownloadInfo downInfo) throws Exception {
return httpservice.download("bytes=" + downInfo.getProgress() + "-", downInfo.getUrl());
}
})//下載
.map(new Function<ResponseBody, DownloadInfo>() {
@Override
public DownloadInfo apply(ResponseBody responsebody) {
try {
return writecache(responsebody, url);
} catch (IOException e) {
//*失敗拋出異常*//
e.printStackTrace();
}
return null;
}
})
.observeOn(AndroidSchedulers.mainThread())//在主線程回調(diào)
.subscribeOn(Schedulers.io())//在子線程執(zhí)行
.subscribeWith(new ProgressDownSubscriber<DownloadInfo>() {
@Override
public void onNext(DownloadInfo downInfo) {
downFileCallback.onSuccess(downInfo);
submap.remove(downInfo.getUrl());
}
@Override
public void onError(Throwable t) {
downFileCallback.onFail(t.getMessage());
submap.remove(url);
}
});
submap.put(url, subscriber);
}
然后暫停操作:
/**
* 暫停下載
*/
public void stop(String url) {
if (url == null) return;
if (submap.containsKey(url)) {
ProgressDownSubscriber subscriber = submap.get(url);
subscriber.dispose();
submap.remove(url);
}
}
從服務(wù)器獲取文件長度
/**
* 從服務(wù)器獲取文件長度
*
* @param downloadUrl
* @return
*/
private long getContentLength(String downloadUrl) {
Request request = new Request.Builder()
.url(downloadUrl)
.build();
try {
Response response = mClient.newCall(request).execute();
if (response != null && response.isSuccessful()) {
long contentLength = response.body().contentLength();
response.close();
return contentLength == 0 ? DownloadInfo.TOTAL_ERROR : contentLength;
}
} catch (IOException e) {
e.printStackTrace();
}
return DownloadInfo.TOTAL_ERROR;
}
從服務(wù)器獲取文件長度的時候注意一下,Android P之后,也就是api 28以上禁止明文網(wǎng)絡(luò)傳輸。需要在你的AndroidManifest中的application標簽中聲明"android:usesCleartextTraffic="true",允許應(yīng)用進行明文傳輸。
使用方法:首先要獲取sd卡權(quán)限
DownloadManager.getInstance().downloadPath(本地存放地址).download(url1, new DownFileCallback() {
@Override
public void onSuccess(DownloadInfo info) {
Toast.makeText(MainActivity.this, url1 + "下載完成", Toast.LENGTH_SHORT).show();
}
@Override
public void onFail(String msg) {
Toast.makeText(MainActivity.this, url1 + "下載失敗", Toast.LENGTH_SHORT).show();
}
@Override
public void onProgress(final long totalSize, final long downSize) {
// 需要注意的是,如果文件總大小為50M,已下載的大小為10M,
// 再次下載時onProgress返回的totalSize是文件總長度
// 減去 已下載大小 10M, 即40M,downSize為本次下載的已下載量
// 好消息是,我已經(jīng)在內(nèi)部做過處理,放心使用吧,但是這個問題大家還是要知道的
runOnUiThread(new Runnable() {
@Override
public void run() {
int progress = (int) (downSize * 100 / totalSize);
progress1.setProgress(progress);
}
});
}
});
好了今天就到這里,希望能幫到大家,這對我來說也是一種加深印象的筆記。
github地址:DownManager 歡迎star
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 很簡單的Java斷點續(xù)傳實現(xiàn)原理
- Java如何實現(xiàn)HTTP斷點續(xù)傳功能
- java實現(xiàn)文件斷點續(xù)傳下載功能
- RxJava+Retrofit+OkHttp實現(xiàn)多文件下載之斷點續(xù)傳
- java斷點續(xù)傳功能實例(java獲取遠程文件)
- Java實現(xiàn)的斷點續(xù)傳功能的示例代碼
- Java編程實現(xiàn)服務(wù)器端支持斷點續(xù)傳的方法(可支持快車、迅雷)
- 基于Java實現(xiàn)多線程下載并允許斷點續(xù)傳
- 命令行使用支持斷點續(xù)傳的java多線程下載器
- java實現(xiàn)文件的斷點續(xù)傳
相關(guān)文章
詳解Java?POI?excel自定義設(shè)置單元格格式
這篇文章主要介紹了Java?POI?excel設(shè)置單元格格式,自定義設(shè)置,設(shè)置單元格格式:來源_formats,更多數(shù)據(jù)類型從formats里面發(fā)現(xiàn),需要的朋友可以參考下2024-01-01
Spring框架JdbcTemplate數(shù)據(jù)庫事務(wù)管理完全注解方式
這篇文章主要介紹了Spring框架JdbcTemplate數(shù)據(jù)庫事務(wù)管理及完全注解方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05
基于javamelody監(jiān)控springboot項目過程詳解
這篇文章主要介紹了基于javamelody監(jiān)控springboot項目過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-11-11
JAVA根據(jù)ip地址獲取歸屬地的實現(xiàn)方法
本文主要介紹了JAVA根據(jù)ip地址獲取歸屬地的實現(xiàn)方法,要通過Java程序獲取IP地址對應(yīng)的城市,需要借助第三方的IP地址庫,下面就來介紹一下,感興趣的可以了解一下2023-10-10
mybatis-plus常用注解@TableId和@TableField的用法
本文主要介紹了mybatis-plus常用注解@TableId和@TableField的用法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
Struts2單選按鈕詳解及枚舉類型的轉(zhuǎn)換代碼示例
這篇文章主要介紹了Struts2單選按鈕詳解及枚舉類型的轉(zhuǎn)換代碼示例,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下2018-02-02
Java實現(xiàn)學(xué)生信息管理系統(tǒng)(借助Array?List)
這篇文章主要為大家詳細介紹了Java實現(xiàn)學(xué)生信息管理系統(tǒng),借助Array?List,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01

