项目中一直用到okHttp3作为网络层,一直想着做一下记录,也一直没写,现在在这里做一下记录。
方法可以直接使用,并且返回下载的进度,当下载中断会生成缓存文件,再次下载相同文件会重新从上次断点处继续下载。
package com.savor.ads.okhttp.coreProgress.download;
import android.text.TextUtils;
import android.util.Log;
import com.savor.ads.service.MiniProgramNettyService;
import com.savor.ads.utils.ConstantValues;
import com.savor.ads.utils.LogFileUtil;
import com.savor.ads.utils.LogUtils;
import org.json.JSONObject;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
/**
* Created by Administrator on 2016/12/9.
* Modify by bichao on 2019-06-25 13:41
*/
public class ProgressDownloader {
public static final String TAG = "ProgressDownloader";
public final static int CONNECT_TIMEOUT =60;
public final static int READ_TIMEOUT=10;
public final static int WRITE_TIMEOUT=10;
private String url;
private OkHttpClient client;
//下载文件存储的位置
private String filePath;
private String fileName;
private long fileSize;
//下载失败重复下载次数,最多3次
private int downloadCount=0;
private Call call;
private MiniProgramNettyService.DownloadProgressListener downloadProgressListener;
public void setDownloadProgressListener(MiniProgramNettyService.DownloadProgressListener listener){
downloadProgressListener = listener;
}
public ProgressDownloader (String url,String filePath,String fileName){
this.url = url;
this.filePath = filePath;
this.fileName = fileName;
//在下载、暂停后的继续下载中可复用同一个client对象
client = getProgressClient();
}
public ProgressDownloader (String url,String filePath,String fileName,long resourceSize){
this.url = url;
this.filePath = filePath;
this.fileName = fileName;
this.fileSize = resourceSize;
//在下载、暂停后的继续下载中可复用同一个client对象
client = getProgressClient();
}
//每次下载需要新建新的Call对象
private Call newRangeCall(long startPoints){
Request request = new Request.Builder()
.url(url)
.header("Range","bytes="+startPoints+"-")//断点续传下载需要用到的,提示下载的区域
.build();
return client.newCall(request);
}
private Call newCall(){
Request request = new Request.Builder()
.url(url)
.build();
return client.newCall(request);
}
public OkHttpClient getProgressClient(){
//拦截器,用上ProgressResponseBody
Interceptor interceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(),fileName))
.build();
}
};
return new OkHttpClient.Builder()
.addNetworkInterceptor(interceptor)
.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)//设置读取超时时间
.writeTimeout(WRITE_TIMEOUT,TimeUnit.SECONDS)//设置写的超时时间
.connectTimeout(CONNECT_TIMEOUT,TimeUnit.SECONDS)//设置连接超时时间
.build();
}
//下载方法
public boolean downloadByRange(){
long startIndex = 0;
boolean flag = false;
try {
File cacheFile = new File(filePath,fileName+ ConstantValues.CACHE);
if (cacheFile.exists()){
RandomAccessFile cacheAccessFile = new RandomAccessFile(cacheFile,"rwd");
try {
startIndex = cacheAccessFile.length();
}catch (NumberFormatException e){
e.printStackTrace();
}
call = newRangeCall(startIndex);
Response response = call.execute();
if (response.code()==206){
flag = saveRangeFile(response,startIndex,cacheFile);
}
}else{
call = newCall();
Response response = call.execute();
if (response.code() == 200) {
flag = saveRangeFile(response,startIndex,cacheFile);
}
}
}catch (Exception e){
e.printStackTrace();
}
return flag;
}
private boolean saveRangeFile(Response response,long startIndex,File cacheFile) throws IOException{
LogFileUtil.writeDownloadLog("下载文件--开始--fileName="+fileName+",fileLength="+startIndex);
boolean flag;
InputStream is = null;
RandomAccessFile tmpAccessFile = new RandomAccessFile(cacheFile, "rw");// 获取前面已创建的文
tmpAccessFile.seek(startIndex);
try {
is = response.body().byteStream();// 获取流
byte[] buffer = new byte[1024*1024*3];
int length;
while ((length = is.read(buffer)) > 0) {//读取流
tmpAccessFile.write(buffer, 0, length);
if (downloadProgressListener!=null&&fileSize!=0){
long cacheLength = tmpAccessFile.length();
countDownlaodProgess(cacheLength,fileSize);
}
}
flag = true;
}catch (Exception e){
flag = false;
e.printStackTrace();
}finally {
if (is!=null){
is.close();
}
close(response);
}
if (flag){
cacheFile.renameTo(new File(filePath+fileName));
LogFileUtil.writeDownloadLog("下载文件--完成--fileName="+fileName+",fileLength="+tmpAccessFile.length());
}else{
if (downloadCount<3){
downloadByRange();
}
downloadCount ++;
}
return flag;
}
//计算出一个百分比的字符串
private void countDownlaodProgess(long currentSize,long totalSize) {
BigDecimal b = new BigDecimal(currentSize * 1.0 / totalSize);
// Log.d("circularProgress", "原始除法得到的值" + currentSize * 1.0 / totalSize);
float f1 = b.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
// Log.d("circularProgress", "保留两位小数得到的值" + f1);
if (f1 >= 0.01f) {
String value = String.valueOf(f1 * 100);
int progress = Integer.valueOf(value.split("\\.")[0]);
downloadProgressListener.getDownloadProgress(progress+"%");
Log.d("downloadProgress", "保留两位小数得到的值" + f1);
}
}
/**
* 关闭资源
*
* @param closeables
*/
private void close(Closeable... closeables) {
int length = closeables.length;
try {
for (int i = 0; i < length; i++) {
Closeable closeable = closeables[i];
if (null != closeable){
closeables[i].close();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
for (int i = 0; i < length; i++) {
closeables[i] = null;
}
}
}
}
package com.savor.ads.okhttp.coreProgress.download;
import android.util.Log;
import com.savor.ads.utils.LogUtils;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;
/**
* 包装的响体,处理进度
* Created by Administrator on 2016/6/14.
*/
public class ProgressResponseBody extends ResponseBody {
private final ResponseBody responseBody;
private String fileName;
private BufferedSource bufferedSource;
public ProgressResponseBody(ResponseBody responseBody, String filename) {
this.responseBody = responseBody;
this.fileName = filename;
}
public ProgressResponseBody(ResponseBody responseBody) {
this.responseBody = responseBody;
}
@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;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
LogUtils.v("fileName="+fileName+":read-----" + totalBytesRead);
return bytesRead;
}
};
}
}