Android 开发 框架系列 OkHttp文件下载功能实现(含断点续传)
前言
此篇博客只是下载功能的记录demo,如果你还不太了解okhttp可以参考我的另一篇博客https://www.cnblogs.com/guanxinjing/p/9708575.html
代码部分
package okhttpdemo.com.libs.net.httpBase;
import android.util.Log;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttpdemo.com.libs.net.httpBase.listener.HttpDownListener;
/**
*@content: okhttp的下载功能工具类 (分别包含:1.无断点续传的get下载 2.有断点续传的get下载 3.无断点续传的post下载 4.有断点续传的post下载)
*@time:2018-12-12
*@build:z
*/ public class OkHttpDownUtil {
private static final String TAG = "OkHttpDownUtil";
private Call mCall;
private long mAlreadyDownLength = 0;//已经下载长度
private long mTotalLength = 0;//整体文件大小
private int mSign = 0; //标记当前运行的是那个方法
private String mDownUrl;//下载网络地址
private File mPath;//文件保存路径
private JSONObject mJson;
private HttpDownListener mHttpDownListener;//下载进度接口回调 /**
* 没有断点续传功能的get请求下载
* @param downUrl 下载网络地址
* @param saveFilePathAndName 保存路径
*/
public void getDownRequest(final String downUrl, final File saveFilePathAndName, final HttpDownListener listener) {
mSign = 1;
mDownUrl = downUrl;
mPath = saveFilePathAndName;
mHttpDownListener = listener;
mAlreadyDownLength = 0;
Request request = new Request.Builder()
.url(mDownUrl)
.get()
.build();
mCall = OkHttpClientCreate.CreateClient().newCall(request);//构建了一个完整的http请求
mCall.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
if (mHttpDownListener != null) {
mHttpDownListener.onFailure(call, e);
} } @Override
public void onResponse(Call call, Response response) throws IOException {
ResponseBody responseBody = response.body();
mTotalLength = responseBody.contentLength();//下载文件的总长度
InputStream inp = responseBody.byteStream();
FileOutputStream fileOutputStream = new FileOutputStream(mPath);
try {
byte[] bytes = new byte[2048];
int len = 0;
while ((len = inp.read(bytes)) != -1) {
mAlreadyDownLength = mAlreadyDownLength + len;
fileOutputStream.write(bytes, 0, len);
if (mHttpDownListener != null) {
mHttpDownListener.onResponse(call, response, mTotalLength, mAlreadyDownLength);
} }
} catch (Exception e) {
Log.e(TAG, "Get下载异常"); } finally {
fileOutputStream.close();
inp.close();
Log.e(TAG, "流关闭");
}
}
});
} /**
* 有断点续传功能的get下载
* @param downUrl 下载地址
* @param saveFilePathAndName 保存路径
* @param listener 进度监听
*/
public void getRenewalDownRequest(final String downUrl, final File saveFilePathAndName, final HttpDownListener listener){
mSign = 2;
mDownUrl = downUrl;
mPath = saveFilePathAndName;
mHttpDownListener = listener;
Request request = new Request.Builder()
.url(mDownUrl)
.header("RANGE", "bytes=" + mAlreadyDownLength + "-")
.build();
mCall = OkHttpClientCreate.CreateClient().newCall(request);//构建了一个完整的http请求
mCall.enqueue(new Callback() { //发送请求
@Override
public void onFailure(Call call, IOException e) {
if (mHttpDownListener != null) {
mHttpDownListener.onFailure(call, e);
}
Log.e(TAG, "onFailure: 异常报错=" + e.toString()); } @Override
public void onResponse(Call call, Response response) throws IOException {
ResponseBody responseBody = response.body();
InputStream inputStream = responseBody.byteStream();//得到输入流
RandomAccessFile randomAccessFile = new RandomAccessFile(mPath, "rw");//得到任意保存文件处理类实例
if (mTotalLength == 0){
mTotalLength = responseBody.contentLength();//得到文件的总字节大小
randomAccessFile.setLength(mTotalLength);//预设创建一个总字节的占位文件
}
if (mAlreadyDownLength != 0){
randomAccessFile.seek(mAlreadyDownLength);
}
byte[] bytes = new byte[2048];
int len = 0;
try {
while ((len = inputStream.read(bytes)) != -1) {
randomAccessFile.write(bytes,0,len);
mAlreadyDownLength = mAlreadyDownLength + len;
if (mHttpDownListener != null) {
mHttpDownListener.onResponse(call, response, mTotalLength, mAlreadyDownLength);
}
} } catch (Exception e) {
Log.e(TAG, "Get下载异常"); } finally {
mAlreadyDownLength = randomAccessFile.getFilePointer();//记录当前保存文件的位置
randomAccessFile.close();
inputStream.close();
Log.e(TAG, "流关闭 下载的位置="+mAlreadyDownLength);
} }
});
} /**
* 没有断点续传的post下载
* @param downUrl
* @param saveFilePathAndName
* @param json
* @param listener
*/
public void postDownRequest(final String downUrl, final File saveFilePathAndName, final JSONObject json,final HttpDownListener listener){
mSign = 3;
mDownUrl = downUrl;
mPath = saveFilePathAndName;
mJson = json;
mHttpDownListener = listener;
mAlreadyDownLength = 0;
Request request = new Request.Builder()
.url(mDownUrl)
.post(changeJSON(json))
.build();
mCall = OkHttpClientCreate.CreateClient().newCall(request);
mCall.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
if (mHttpDownListener!=null){
mHttpDownListener.onFailure(call,e);
}
} @Override
public void onResponse(Call call, Response response) throws IOException { ResponseBody responseBody = response.body();
mTotalLength = responseBody.contentLength();
InputStream inputStream = responseBody.byteStream();
FileOutputStream fileOutputStream = new FileOutputStream(mPath);
byte[] bytes = new byte[2048];
int len = 0;
try {
while ((len = inputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, len);
mAlreadyDownLength = mAlreadyDownLength + len;
if (mHttpDownListener != null) {
mHttpDownListener.onResponse(call, response, mTotalLength, mAlreadyDownLength);
}
}
}catch (Exception e){
Log.e(TAG, "Post下载异常");
}finally {
fileOutputStream.close();
inputStream.close();
Log.e(TAG, "流关闭"); } } }); } /**
* 支持断点续传的post下载
* @param downUrl 下载网址
* @param saveFilePathAndName 文件保存路径
* @param json 参数
* @param listener 接口回调
*/
public void postRenewalDownRequest(final String downUrl, final File saveFilePathAndName, final JSONObject json, final HttpDownListener listener){
mSign = 4;
mDownUrl = downUrl;
mPath = saveFilePathAndName;
mJson = json;
mHttpDownListener = listener;
Request request = new Request.Builder()
.url(mDownUrl)
.header("RANGE","bytes="+mAlreadyDownLength+"-")
.post(changeJSON(json))
.build();
mCall = OkHttpClientCreate.CreateClient().newCall(request);
mCall.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
if (mHttpDownListener != null){
mHttpDownListener.onFailure(call,e);
}
} @Override
public void onResponse(Call call, Response response) throws IOException {
ResponseBody responseBody = response.body();
InputStream inputStream = responseBody.byteStream();
RandomAccessFile randomAccessFile = new RandomAccessFile(mPath,"rw");
if (mTotalLength == 0){
mTotalLength = responseBody.contentLength();
randomAccessFile.setLength(mTotalLength);
}
if (mAlreadyDownLength!=0){
randomAccessFile.seek(mAlreadyDownLength);
}
byte[] bytes = new byte[2048];
int len = 0;
try {
while ((len = inputStream.read(bytes)) != -1) {
randomAccessFile.write(bytes, 0, len);
mAlreadyDownLength = mAlreadyDownLength + len;
if (mHttpDownListener != null) {
mHttpDownListener.onResponse(call, response, mTotalLength, mAlreadyDownLength);
} }
}catch (Exception e){
Log.e(TAG, "Post下载异常"); }finally {
mAlreadyDownLength = randomAccessFile.getFilePointer();
randomAccessFile.close();
inputStream.close();
Log.e(TAG, "流关闭 下载的位置="+mAlreadyDownLength);
} }
});
} /**
* 恢复下载
*/
public void resume(){
if (mSign==0){
return;
}
switch (mSign){
case 1:
getDownRequest(mDownUrl,mPath,mHttpDownListener);
break;
case 2:
getRenewalDownRequest(mDownUrl,mPath,mHttpDownListener);
break;
case 3:
postDownRequest(mDownUrl,mPath,mJson,mHttpDownListener);
break;
case 4:
postRenewalDownRequest(mDownUrl,mPath,mJson,mHttpDownListener);
break;
default:
break;
} } /**
* 暂停下载
*/
public void stop(){
if (mCall!=null){
mCall.cancel();
} } /**
* 删除下载文件
*/
public void deleteCurrentFile(){
if (mPath == null){
Log.e(TAG, "deleteCurrentFile error : 没有路径");
return;
}
if (!mPath.exists()){
Log.e(TAG, "deleteCurrentFile error: 文件不存在");
return;
}
mPath.delete();
mAlreadyDownLength = 0;
mTotalLength = 0;
mSign = 0;
} /**
* 销毁
*/
public void destroy(){
if (mCall!=null){
mCall.cancel();
mCall = null;
}
mSign = 0;
mDownUrl = null;
mPath = null;
mHttpDownListener = null;
mAlreadyDownLength = 0;
mTotalLength = 0;
} /**
* 转换Json参数为RequestBody
* @param jsonParam json对象
* @return RequestBody
*/
private RequestBody changeJSON(JSONObject jsonParam){
RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8")
, String.valueOf(jsonParam));
return requestBody;
} }
Android 开发 框架系列 OkHttp文件下载功能实现(含断点续传)的更多相关文章
- Android 开发 框架系列 OkHttp拦截器
前言 此篇博客只讲解okhttp的拦截器功能的详细使用,如果你还不太了解okhttp可以参考我另外一篇博客 Android 开发 框架系列 OkHttp使用详解 添加Interceptor的简单例子 ...
- Android 开发 框架系列 OkHttp使用详解
简介 okhttp是一个第三方类库,用于android中请求网络.这是一个开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso和LeakCanary) . ...
- Android 开发 框架系列 OkHttp文件上传功能实现(含断点续传)
前言 此篇博客只是上传功能的记录demo,如果你还不太了解okhttp可以参考我的另一篇博客https://www.cnblogs.com/guanxinjing/p/9708575.html 代码部 ...
- Android 开发 框架系列 Google的ORM框架 Room
目录 简介 导入工程 使用流程概况 一个简单的小Demo 深入学习 @Entity使用 自定义表名 tableName 自定义字段名@ColumnInfo 主键 @PrimaryKey 索引 @In ...
- android 开发 框架系列 使用 FileDownloader 实现检查更新的功能class
首先介绍一下FileDownloader GH :https://github.com/lingochamp/FileDownloader/blob/master/README-zh.md FileD ...
- Android 开发 框架系列 百度语音合成
官方文档:http://ai.baidu.com/docs#/TTS-Android-SDK/6d5d6899 官方百度语音合成控制台:https://cloud.baidu.com/product/ ...
- Android 开发 框架系列 EventBus 事件总线
介绍 GitHub:https://github.com/greenrobot/EventBus 先聊聊EventBus 线程总线是干什么的,使用环境,优点.缺点. 干什么的? 一句话,简单统一数据传 ...
- Android 开发 框架系列 glide-transformations 图片处理基本使用
首先简单的介绍一下Gilde作用范围.Gilde功能十分强大,它可以实现图片处理.图片本地加载.图片网络加载.位图加载.图片内存缓存.图片磁盘缓存.Gif图片加载.使用简单轻松,轻松的后是它强大的心, ...
- Android 开发 框架系列 Android-Universal-Image-Loader 图片加载使用demo
Android-Universal-Image-Loader github地址:https://github.com/nostra13/Android-Universal-Image-Loader 加 ...
随机推荐
- VC++ 2010 创建高级Ribbon界面详解(3)
3.工具栏 在传统的菜单式界面中,工具栏作为菜单的有益补充,被广泛使用.我们通过将一些常用命令放置到工具栏上,可以让用户直观而快速地访问到常用功能,提高了效率.在Ribbon界面中,工具栏得到了进一步 ...
- response和ServletContext和乱码问题
服务器端以/开始就代表当前项目名客户端必须以 /项目名/资源 才能定位到资源 软件与软件之间,以字符为标准传递,传递字节,接收端自己按原来的编码集编码之后再按照自己的编码集解码编码(如果没有对应字符, ...
- Java设计模式思想(单列模式,工厂模式,策略模式)
a) 单例模式:单例模式核心只需要new一个实例对象的模式,比如数据库连接,在线人数等,一些网站上看到的在线人数统计就是通过单例模式实现的,把一个计时器存放在数据库或者内存中,当有人登陆的时候取出来加 ...
- Exception一自定义异常
异常体系的根类是:Throwable Throwable: Error: 重大的问题,我们处理不了.也不需要编写代码处理.比如说内存溢出. Exception: 一般性的错误,是需要我们对编写 ...
- BOM的介绍
BOM的概念 BOM(Browser Object Model) 是指浏览器对象模型,浏览器对象模型提供了独立于内容的.可以与浏览器窗口进行互动的对象结构.BOM由多个对象组成,其中代表浏览器窗口的W ...
- bzoj3505: [Cqoi2014]数三角形 [数论][gcd]
Description 给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个.下图为4x4的网格上的一个三角形. 注意三角形的三点不能共线. Input 输入一行,包含两个空格分隔的正整数m和 ...
- linux源码安装python及pip和django
1安装编译工具 yum install zlib-devel bzip2-devel openssl-devel python-devel kernel-devel libffi-devel ncur ...
- kafka-manager监控工具的安装和使用
kafka-manager监控工具的使用 第一步:对kafkamanager进行下载并编译 此步骤略:可参照成功与否不详,https://www.jianshu.com/p/174b6eb10d9d ...
- NX二次开发-UFUN获取工程图视图边界线是否显示UF_DRAW_ask_border_display
#include <uf.h> #include <uf_draw.h> #include <uf_ui.h> UF_initialize(); logical b ...
- [JZOJ 5817] 抄代码
题意: 给定2T个串,带修的判断两个串是否按规则一样?? 思路: 两个串是"抄袭的"肯定就是: 1.长度一样. 2.特殊字符位置一样 3.对于每个\(x\)在两个串中出现位置一样, ...