基于Ok+Rxjava實(shí)現(xiàn)斷點(diǎn)續(xù)傳下載
本文為大家分享了實(shí)現(xiàn)斷點(diǎn)續(xù)傳下載的具體代碼,供大家參考,具體內(nèi)容如下
1、基于Ok+Rxjava實(shí)現(xiàn)斷點(diǎn)續(xù)傳下載
2、基于Ok+Rxjava+Retrofit實(shí)現(xiàn)斷點(diǎn)續(xù)傳下載
最近總結(jié)一下了一下之前學(xué)過(guò)以及用到過(guò)得功能,整理了一個(gè)基于Ok+Rxjava實(shí)現(xiàn)斷點(diǎn)續(xù)傳下載的demo。下面先給大家展示一下使用效果吧。

說(shuō)下我的大致思路吧:根據(jù)文件下載url按照自己定義的規(guī)則生成文件名,判斷本地同路徑下是否存在此文件,如果存在,文件大小與服務(wù)器上獲取的文件大小一致的情況下,則生成新的文件名重新下載;如果文件比服務(wù)器獲取的文件大小小,則執(zhí)行斷點(diǎn)下載,從本地文件長(zhǎng)度處開(kāi)始下載。如果文件不存在,則從0字節(jié)開(kāi)始下載。
DownloadSubscribe(被觀察者)中執(zhí)行下載存入本地操作
核心還是:addHeader("RANGE", "bytes=" + downloadLength + "-" + contentLength)
DownLoadObserver(觀察者)通過(guò)onnext(DownloadInfo downloadInfo)方法回調(diào)下載進(jìn)度
下面上主要代碼:
/**
* 開(kāi)始下載
* @param url 下載請(qǐng)求的網(wǎng)址
* @param downFileCallback 用來(lái)回調(diào)的接口
*/
public void download(final String url, final DownFileCallback downFileCallback) {
if (url == null || downCalls.get(url) != null) {
return;
}
Observable.just(url)
.filter(new Predicate<String>() {
@Override
public boolean test(String s) throws Exception {
//過(guò)濾條件 若map中存在,則這次不下載
return !downCalls.containsKey(s);
}
})
.flatMap(new Function<String, ObservableSource<DownloadInfo>>() {
@Override
public ObservableSource<DownloadInfo> apply(String s) throws Exception {
//創(chuàng)建下載實(shí)體類
return Observable.just(createDownInfo(s));
}
})
.map(new Function<DownloadInfo, DownloadInfo>() {
@Override
public DownloadInfo apply(DownloadInfo s) throws Exception {
//根據(jù)本地是否存在此文件,來(lái)設(shè)置文件名及文件初始下載大小
return getRealFileName(s);
}
})
.flatMap(new Function<DownloadInfo, ObservableSource<DownloadInfo>>() {
@Override
public ObservableSource<DownloadInfo> apply(DownloadInfo downloadInfo) throws Exception {
//創(chuàng)建被觀察者
return Observable.create(new DownloadSubscribe(downloadInfo));
}
})//下載
.observeOn(AndroidSchedulers.mainThread())//在主線程回調(diào)
.subscribeOn(Schedulers.io())//在子線程執(zhí)行
.subscribe(new DownLoadObserver() {//添加觀察者
@Override
public void onNext(DownloadInfo downloadInfo) {
super.onNext(downloadInfo);
downFileCallback.onProgress(downloadInfo.getTotal(), downloadInfo.getProgress());
}
@Override
public void onError(Throwable e) {
super.onError(e);
if (!(e instanceof SocketException)) {
downFileCallback.onFail(e.getMessage());
}
}
@Override
public void onComplete() {
downFileCallback.onSuccess(url);
}
});
}
/**
* 根據(jù)url暫停下載操作
* @param url
*/
public void cancel(String url) {
Call call = downCalls.get(url);
if (call != null) {
call.cancel();//取消
}
downCalls.remove(url);
}
/**
* 創(chuàng)建被觀察者DownloadSubscribe
*/
private class DownloadSubscribe implements ObservableOnSubscribe<DownloadInfo> {
private DownloadInfo downloadInfo;
public DownloadSubscribe(DownloadInfo downloadInfo) {
this.downloadInfo = downloadInfo;
}
@Override
public void subscribe(ObservableEmitter<DownloadInfo> e) throws Exception {
String url = downloadInfo.getUrl();
long downloadLength = downloadInfo.getProgress();//已經(jīng)下載好的長(zhǎng)度
long contentLength = downloadInfo.getTotal();//文件的總長(zhǎng)度
//初始進(jìn)度信息
e.onNext(downloadInfo);
Request request = new Request.Builder()
//斷點(diǎn)續(xù)傳的核心
.addHeader("RANGE", "bytes=" + downloadLength + "-" + contentLength)
.url(url)
.build();
Call call = mClient.newCall(request);
//根據(jù)下載url,把call存放在map中,取消的時(shí)候就可以通過(guò)call.cancle()來(lái)實(shí)現(xiàn)
downCalls.put(url, call);
Response response = call.execute();
File file = new File(getTemporaryPath(), downloadInfo.getFileName());
InputStream is = null;
FileOutputStream fileOutputStream = null;
try {
is = response.body().byteStream();
fileOutputStream = new FileOutputStream(file, true);
byte[] buffer = new byte[2048];//緩沖數(shù)組2kB
int len;
while ((len = is.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, len);
downloadLength += len;
downloadInfo.setProgress(downloadLength);
e.onNext(downloadInfo);
}
fileOutputStream.flush();
downCalls.remove(url);
} finally {
//關(guān)閉IO流
IOUtil.closeAll(is, fileOutputStream);
}
e.onComplete();//完成
}
}
/**
* 從服務(wù)器獲取文件長(zhǎng)度
*
* @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ù)器獲取文件長(zhǎng)度的時(shí)候注意一下,Android P之后,也就是api 28以上禁止明文網(wǎng)絡(luò)傳輸。需要在你的AndroidManifest中的application標(biāo)簽中聲明"android:usesCleartextTraffic="true",允許應(yīng)用進(jìn)行明文傳輸。
使用方法:首先要獲取sd卡權(quán)限
DownloadManager.getInstance().downloadPath(本地存在地址).download(url1, new DownFileCallback() {
@Override
public void onProgress(long totalSize, long downSize) {
progress1.setMax((int) totalSize);
progress1.setProgress((int) downSize);
}
@Override
public void onSuccess(String url) {
Toast.makeText(MainActivity.this, url1 + "下載完成", Toast.LENGTH_SHORT).show();
}
@Override
public void onFail(String msg) {
Toast.makeText(MainActivity.this, url1 + "下載失敗", Toast.LENGTH_SHORT).show();
}
});
好了今天就到這里,希望能幫到大家,這對(duì)我來(lái)說(shuō)也是一種加深印象的筆記,
下載地址demo
git地址:DownloadManager 歡迎star
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用restTemplate.postForEntity()的問(wèn)題
這篇文章主要介紹了使用restTemplate.postForEntity()的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
java簡(jiǎn)單實(shí)現(xiàn)斗地主發(fā)牌功能
這篇文章主要為大家詳細(xì)介紹了java簡(jiǎn)單實(shí)現(xiàn)斗地主發(fā)牌功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
學(xué)習(xí)Java之自定義異常與NullPointerException的處理
有時(shí)候Java自身提供的異常類并不能很好地表達(dá)我們的需求,所以這時(shí)候我們就可以自定義異常,也就是說(shuō),我們可以制造出一個(gè)自己的異常類,這樣就可以拋出或捕獲自己的異常了,本文就給大家詳細(xì)講講Java自定義異常與NullPointerException的處理2023-08-08
解決SpringBoot返回結(jié)果如果為null或空值不顯示處理問(wèn)題
這篇文章主要介紹了解決SpringBoot返回結(jié)果如果為null或空值不顯示處理問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
利用Spring AOP記錄方法的執(zhí)行時(shí)間
這篇文章給大家介紹的是spring的aop來(lái)實(shí)現(xiàn)方法級(jí)的執(zhí)行時(shí)間的記錄監(jiān)控,以此來(lái)評(píng)估方法的性能以及針對(duì)性的對(duì)已存在的方法進(jìn)行優(yōu)化。對(duì)于監(jiān)控,我們比較關(guān)注監(jiān)控的可靠性和性能,準(zhǔn)確,高效,這才能在不影響整體性能的情況下對(duì)我們的系統(tǒng)性能有個(gè)較準(zhǔn)確的認(rèn)識(shí)。2016-09-09
SpringBoot應(yīng)用整合ELK實(shí)現(xiàn)日志收集的示例代碼
這篇文章主要介紹了SpringBoot應(yīng)用整合ELK實(shí)現(xiàn)日志收集的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
MybatisPlus的IPage失效的問(wèn)題解決方案
這篇文章主要介紹了MybatisPlus的IPage失效的問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01

