基于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)文章
SpringBoot3集成Swagger3的詳細(xì)教程
Swagger 3(OpenAPI 3.0)提供了更加強(qiáng)大和靈活的API文檔生成能力,本教程將指導(dǎo)您如何在Spring Boot 3項(xiàng)目中集成Swagger3,并使用Knife4j作為UI界面,需要的朋友可以參考下2024-03-03
MyBatisPlus中批量插入之如何通過(guò)開(kāi)啟rewriteBatchedStatements=true
這篇文章主要介紹了MyBatisPlus中批量插入之如何通過(guò)開(kāi)啟rewriteBatchedStatements=true問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03
SpringBoot整合minio快速入門(mén)教程(代碼示例)
這篇文章主要介紹了SpringBoot整合minio快速入門(mén)實(shí)現(xiàn)文件上傳和下載的示例代碼,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04
Java日志相關(guān)技術(shù)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了Java日志相關(guān)技術(shù)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理的相關(guān)資料,需要的朋友可以參考下2017-07-07
Spring Native實(shí)現(xiàn)0.059s啟動(dòng)一個(gè)SpringBoot項(xiàng)目
Spring Native是Spring框架的一個(gè)子項(xiàng)目,旨在提供一種將Spring應(yīng)用程序編譯為本地可執(zhí)行文件的方法,從而提高啟動(dòng)時(shí)間和資源效率,本文主要介紹了Spring Native實(shí)現(xiàn)0.059s啟動(dòng)一個(gè)SpringBoot項(xiàng)目,感興趣的可以了解一下2024-02-02
JAVA實(shí)現(xiàn)對(duì)阿里云DNS的解析管理
本文主要介紹了JAVA實(shí)現(xiàn)對(duì)阿里云DNS的解析管理,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
在CentOS系統(tǒng)上安裝Java?JDK?8簡(jiǎn)單步驟
最近購(gòu)買一臺(tái)新的云服務(wù)器,用于開(kāi)發(fā)學(xué)習(xí)使用,因此需要安裝很多的組件,下面這篇文章主要給大家介紹了關(guān)于在CentOS系統(tǒng)上安裝Java?JDK8的簡(jiǎn)單步驟,需要的朋友可以參考下2023-12-12

