Retrofit 2.0 超能实践(四),完成大文件断点下载
2016-07-21 22:54
651 查看
作者:码小白
文/CSDN 博客
本文出自:http://blog.csdn.net/sk719887916/article/details/51988507 码小白
通过前几篇系统的介绍和综合运用,忘记介绍文件下载功能了,有朋友问到,目前APP文件下载主要有断点续传,多线程并发下载,多类型下载,今天就介绍下其Retrofit下载文件功能。
Retrofit 2.0
超能实践,完美支持Https传输
Retrofit2.0
完美同步Cookie实现免登录
Retrofit 2.0 超能实践(三),轻松实现文件/图片上传
基于Retrofit2.0 封装的超好用的RetrofitClient工具类
玩转IOC,教你徒手实现自定义的Retrofit框架
url由于是可变的,因此用
}
上面只是简单的对不同类型文件进行了判断,其他类型参考
当 然我们可以在header中加入上次下载的进度大小,就可以实现基本的断点下载了,多线程下载目前业内主要由下面思想实现,我们可以请求到文件总长度的时候,均分三段大小区间,来开启三个新线程去下载,下载完后再以唯一的文件ID,将三段文件以此追加到一个文件就可以了,当然在retrofit结合RxJava,你无需开启新线程,只需订阅一下 Subscriber到IO线程即可,这里注意的是你需要判断最后的文件大小和HashCode来进行验证文件完整性,不然视频文件丢包了没多大区别,最多会卡帧,但是apk丢包了却无法解析安装了。
断点下载姿势开启!
DownloadType 里面记录要有stats,mLastModify,downloded ,savepath等
开始下载:
请求文件总大小
根据机型高低,分配多个线程下载
记录下载进度,大小,类型等到数据库
同时更新UI和通知栏,提示用户
下载结束后更新数据库下载数据,追加组合文件
判断文件大小,检验文件大小
下载功能是每个应用必须的功能,因此下载还是比较重要的一个模块,好的下载架构 会考虑到设备的CPU大小,网络状态,以及外部sdcard的大小,动态进行性能,流量分配,方便用户更好的体验和使用你的APP.
具体可以阅读 - 基于Retrofit2.0 封装的超好用的RetrofitClient工具类 中的写法
项目github:https://github.com/Tamicer/FastDownloader
文/CSDN 博客
本文出自:http://blog.csdn.net/sk719887916/article/details/51988507 码小白
通过前几篇系统的介绍和综合运用,忘记介绍文件下载功能了,有朋友问到,目前APP文件下载主要有断点续传,多线程并发下载,多类型下载,今天就介绍下其Retrofit下载文件功能。
Retrofit 2.0
超能实践,完美支持Https传输
Retrofit2.0
完美同步Cookie实现免登录
Retrofit 2.0 超能实践(三),轻松实现文件/图片上传
基于Retrofit2.0 封装的超好用的RetrofitClient工具类
玩转IOC,教你徒手实现自定义的Retrofit框架
ApiService
编写API,执行下载接口功能。public interface ApiService { @Streaming @GET Observable<ResponseBody> downloadFile(@Url String fileUrl); }
url由于是可变的,因此用
@URL注解符号来进行指定,大文件官方建议用
@Streaming来进行注解,不然会出现IO异常,小文件可以忽略不注入。如果想进行断点续传的话 可以在此加入header,但不建议直接在api中写死,每个下载的请求大小是不同的,在拦截器加入更为妥善。
DownLoadManager
实现一个下载管理者 来进行文件写入,类型判断等,如果想做完善,可以判断下http的请求头content-length,
content- type,
RANGE第一个用来判断文件大小,第二个文件类型,第三个是文件从哪儿开始下载,如果对下载来源校验可以加入
referer, 不是目标来源的可以不予下载权限。
public class DownLoadManager { private static final String TAG = "DownLoadManager"; private static String APK_CONTENTTYPE = "application/vnd.android.package-archive"; private static String PNG_CONTENTTYPE = "image/png"; private static String JPG_CONTENTTYPE = "image/jpg"; private static String fileSuffix=""; public static boolean writeResponseBodyToDisk(Context context, ResponseBody body) { Log.d(TAG, "contentType:>>>>"+ body.contentType().toString()); String type = body.contentType().toString(); if (type.equals(APK_CONTENTTYPE)) { fileSuffix = ".apk"; } else if (type.equals(PNG_CONTENTTYPE)) { fileSuffix = ".png"; } // 其他同上 自己判断加入 String path = context.getExternalFilesDir(null) + File.separator + System.currentTimeMillis() + fileSuffix; Log.d(TAG, "path:>>>>"+ path); try { // todo change the file location/name according to your needs File futureStudioIconFile = new File(path); InputStream inputStream = null; OutputStream outputStream = null; try { byte[] fileReader = new byte[4096]; long fileSize = body.contentLength(); long fileSizeDownloaded = 0; inputStream = body.byteStream(); outputStream = new FileOutputStream(futureStudioIconFile); while (true) { int read = inputStream.read(fileReader); if (read == -1) { break; } outputStream.write(fileReader, 0, read); fileSizeDownloaded += read; Log.d(TAG, "file download: " + fileSizeDownloaded + " of " + fileSize); } outputStream.flush(); return true; } catch (IOException e) { return false; } finally { if (inputStream != null) { inputStream.close(); } if (outputStream != null) { outputStream.close(); } } } catch (IOException e) { return false; } }
}
上面只是简单的对不同类型文件进行了判断,其他类型参考
http协议描述类型自行加入,断点续传目前暂时没实现,基于HttpClinet下载的介绍很多,关键思想是记录一条下载产生后的
RANGE到数据库里,每条下载行对应一条数据,下载ID是区分唯一的主键, 包含
filename,
fileSize, fileType, downTime, downRange
status基本可满足多线程下载数据要求,在Retrofit结合RXJava后 解决了线程安全问题,实现多线程下载就更so yi z, 这里我也不做多的介绍。
调用下载
OkHttpClient okHttpClient = new OkHttpClient.Builder() .build(); Retrofit retrofit = new Retrofit.Builder() .client(okHttpClient) .baseUrl(url) .build(); Api Service apiService = retrofit.create(ApiService.class); apiService..download(url1, new Subscriber<ResponseBody>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(ResponseBody responseBody) { if (DownLoadManager.writeResponseBodyToDisk(MainActivity.this, responseBody)) { Toast.makeText(MainActivity.this, "Download is sucess", Toast.LENGTH_LONG).show(); } } }); } });
当 然我们可以在header中加入上次下载的进度大小,就可以实现基本的断点下载了,多线程下载目前业内主要由下面思想实现,我们可以请求到文件总长度的时候,均分三段大小区间,来开启三个新线程去下载,下载完后再以唯一的文件ID,将三段文件以此追加到一个文件就可以了,当然在retrofit结合RxJava,你无需开启新线程,只需订阅一下 Subscriber到IO线程即可,这里注意的是你需要判断最后的文件大小和HashCode来进行验证文件完整性,不然视频文件丢包了没多大区别,最多会卡帧,但是apk丢包了却无法解析安装了。
断点下载姿势开启!
断点下载
apiServiece
@GET @Streaming Observable<Response<ResponseBody>> download(@Header("Range") String range, @Url String url);
API
**DownLoadInfo**s里面包含name,lenth,.url,等,这里不再贴了。直接看APIDownloadType 里面记录要有stats,mLastModify,downloded ,savepath等
public Observable<DownloadInfos> download(@NonNull final String url, @NonNull final String saveName, @Nullable final String savePath) { return downloadDispatcher(url, saveName, savePath); } private Observable<DownloadStatus> downloadDispatcher(final String url, final String saveName, final String savePath) { return getDownloadType(url) .flatMap(new Func1<DownloadType, Observable<DownloadStatus>>() { @Override public Observable<DownloadInfos> call(DownloadType type) { try { type.prepare(); } catch (IOException | ParseException e) { return Observable.error(e); } try { return type.start(); } catch (IOException e) { return Observable.error(e); } } }) .doOnCompleted(new Action0() { @Override public void call() { mDownloadManager.delete(url); } }) .doOnError(new Action1<Throwable>() { @Override public void call(Throwable throwable) { mDownloadManager.delete(url); } }) .doOnUnsubscribe(new Action0() { @Override public void call() { mDownloadManager.delete(url) }); }
开始下载:
@Override Observable<DownloadInfos> start() { Log.i(TAG, "Normal download start!!"); return mDownloadHelper.getDownloadApi().download(null, mUrl) .subscribeOn(Schedulers.io()) .flatMap(new Func1<Response<ResponseBody>, Observable<DownloadStatus>>() { @Override public Observable<DownloadStatus> call(final Response<ResponseBody> response) { return normalSave(response); } }).onBackpressureLatest().retry(new Func2<Integer, Throwable, Boolean>() { @Override public Boolean call(Integer integer, Throwable throwable) { return mDownloadHelper.retry(integer, throwable); } }); }
调用
DownloadAgenti.getInstance(mContext) .observeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<DownloadInfos>() { @Override public void onCompleted() { // todo } @Override public void onError(Throwable e) { todo } @Override public void onNext(final DownloadStatus status) { todo } });
总结
步骤:请求文件总大小
根据机型高低,分配多个线程下载
记录下载进度,大小,类型等到数据库
同时更新UI和通知栏,提示用户
下载结束后更新数据库下载数据,追加组合文件
判断文件大小,检验文件大小
下载功能是每个应用必须的功能,因此下载还是比较重要的一个模块,好的下载架构 会考虑到设备的CPU大小,网络状态,以及外部sdcard的大小,动态进行性能,流量分配,方便用户更好的体验和使用你的APP.
具体可以阅读 - 基于Retrofit2.0 封装的超好用的RetrofitClient工具类 中的写法
项目github:https://github.com/Tamicer/FastDownloader
相关文章推荐
- Python3写爬虫(四)多线程实现数据爬取
- Scrapy的架构介绍
- 发布一个自己做的jsp博客系统
- 提供个 全免杀海洋2006asp木马 下载
- 高手写的Tracer-Flash代码调试类代码下载
- Vista 防火墙 Vista Firewall Control v1.0.11 下载
- 国外Lightbox v2.03.3 最新版 下载
- C#实现多线程的同步方法实例分析
- 火影漫画下载助手 下载
- USBkill U盘防火墙 v3.0 下载
- 腾讯 Tencent Traveler v3.4 下载
- 查杀软件 360安全卫士 v3.2.1.1001 下载
- Kaspersky 6.0.2.666 MP2 nct Release+汉化补丁 下载
- Symantec Norton Ghost v12.0 Retail ISO 多国语言版 下载
- 电脑硬件分析Ultimate Boot CD v4.1.1 下载
- 花香盈路7.6商业美化版 下载
- Orca (Msi文件编辑器) 3.1.4000.1830 修正 汉化版 下载
- 办公室文档模板集合 下载
- Adobe Shockwave Player v10.2.0.022 下载
- 太平洋软件下载站SQL全功能新云2.1商业版代码 下载