本文为大家分享了实现断点续传下载的具体代码,供大家参考,具体内容如下
1、基于Ok+Rxjava实现断点续传下载
2、基于Ok+Rxjava+Retrofit实现断点续传下载
上一篇博客中介绍了基于Ok+Rxjava实现断点续传下载,这一篇给大家介绍下基于Ok+Rxjava+Retrofit实现断点续传下载,demo下载地址,效果图跟上一篇图片一样,哈哈
说下我的大致思路吧(跟上一篇略有不同):根据文件下载url按照自己定义的规则生成文件名,判断本地同路径下是否存在此文件,如果存在,文件大小与服务器上获取的文件大小一致的情况下,则覆盖本地文件重新下载;如果文件比服务器获取的文件大小小,则执行断点下载,从本地文件长度处开始下载。如果文件不存在,则从0字节开始下载。
还有的不同是,这里需要重新ResponseBody的source()方法,在这里监听文件下载的进度,然后通过我么自定义的Downloadinterceptor把我们重新的DownloadResponseBody给设置进去,从而完成我们的进度监听工作。
下面还是上主要代码:
首先重写ResponseBody
public class DownloadResponseBody extends ResponseBody { private ResponseBody responseBody; //进度回调接口 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这个判断,防止下载过程中写入到内存中,造成oom*/ @Streaming @GET Observable<ResponseBody> download(@Header("range") String start, @Url String url); }
接下来我们的DownloadManager中download方法
/** * 开始下载 * @param url 下载地址 * @param downFileCallback 进度回调接口 */ 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())//在主线程回调 .subscribeOn(Schedulers.io())//在子线程执行 .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); } }
从服务器获取文件长度
/** * 从服务器获取文件长度 * * @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; }
从服务器获取文件长度的时候注意一下,Android P之后,也就是api 28以上禁止明文网络传输。需要在你的AndroidManifest中的application标签中声明"android:usesCleartextTraffic="true",允许应用进行明文传输。
使用方法:首先要获取sd卡权限
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为本次下载的已下载量 // 好消息是,我已经在内部做过处理,放心使用吧,但是这个问题大家还是要知道的 runOnUiThread(new Runnable() { @Override public void run() { int progress = (int) (downSize * 100 / totalSize); progress1.setProgress(progress); } }); } });
好了今天就到这里,希望能帮到大家,这对我来说也是一种加深印象的笔记。
demo下载地址
github地址:DownManager 欢迎star
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍基于Ok+Rxjava实现断点续传下载,包括了基于Ok+Rxjava实现断点续传下载的使用技巧和注意事项,需要的朋友参考一下 本文为大家分享了实现断点续传下载的具体代码,供大家参考,具体内容如下 1、基于Ok+Rxjava实现断点续传下载 2、基于Ok+Rxjava+Retrofit实现断点续传下载 最近总结一下了一下之前学过以及用到过得功能,整理了一个基于Ok+Rxjava实现断点
本文向大家介绍基于断点续传下载原理的实现,包括了基于断点续传下载原理的实现的使用技巧和注意事项,需要的朋友参考一下 需求背景 动态创建的文件下载的时候希望浏览器显示下载进度 动态创建的文件希望能够分段下载 HTTP断点续传报文 要实现HTTP断点续传必须要简单了解以下几个报文。 Accept-Ranges 告诉客户端(浏览器..)服务器端支持断点续传 服务器端返回 Range 客户端告诉服务器端从
本文向大家介绍PHP实现下载断点续传的方法,包括了PHP实现下载断点续传的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了PHP实现下载断点续传的方法。分享给大家供大家参考。 具体实现代码如下: 希望本文所述对大家的PHP程序设计有所帮助。
本文向大家介绍Retrofit+Rxjava实现文件上传和下载功能,包括了Retrofit+Rxjava实现文件上传和下载功能的使用技巧和注意事项,需要的朋友参考一下 Retrofit简介: 在Android API4.4之后,Google官方使用了square公司推出的okHttp替换了HttpClient的请求方式。后来square公司又推出了基于okHttp的网络请求框架:Retrofit。
本文向大家介绍C# 文件下载之断点续传实现代码,包括了C# 文件下载之断点续传实现代码的使用技巧和注意事项,需要的朋友参考一下 注意,本文所说的断点续传特指 HTTP 协议中的断点续传。本文主要聊聊思路和关键代码,更多细节请参考本文附带的 demo。 工作原理 HTTP 协议中定义了一些请求/响应头,通过组合使用这些头信息。我们可以在一次 HTTP 请求中只请求一个文件中的一部分数据。这样我们就可
本文向大家介绍Android通过HTTP协议实现断点续传下载实例,包括了Android通过HTTP协议实现断点续传下载实例的使用技巧和注意事项,需要的朋友参考一下 整理文档,搜刮出一个Android通过HTTP协议实现断点续传下载的代码,稍微整理精简一下做下分享。 FileDownloader.java