Android HttpUrlConnection 断点下载

2024-06-24 06:58

本文主要是介绍Android HttpUrlConnection 断点下载,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

在经过一段时间使用OKHttp之后,偶尔需要应用别人的jar,但是别人的jar中已经包含了OKHttp之后,又是各种麻烦修改,考虑种种之后想办法自己在HttpUrlConnection方面写一个断点下载,同时如果自己不需要断点下载,简单的设置以下就可以了。

知识点

(1)断点传递给服务器端,请求需要的从断点开始的数据

// 统一资源
URL httpUrl = new URL(url);
// 连接类的父类,抽象类
URLConnection urlConnection = httpUrl.openConnection();
// http的连接类
HttpURLConnection httpURLConnection = (HttpURLConnection) httpUrl.openConnection();
if (url.toUpperCase().startsWith("HTTPS")) {httpURLConnection = (HttpURLConnection) urlConnection;HttpsURLConnection httpsURLConnection = (HttpsURLConnection) httpURLConnection;httpsURLConnection.setHostnameVerifier(new HttpsHostnameVerifier());httpsURLConnection.setSSLSocketFactory(HttpsSSLSocketFactory.factory());httpURLConnection = httpsURLConnection;
}
httpURLConnection.setDoInput(true);
// 设定请求的方法,默认是GET
httpURLConnection.setRequestMethod("GET");
// 设置字符编码
httpURLConnection.setRequestProperty("Charset", "UTF-8");
long downloadedLength = calculateDownloadedLength(url);//设置下载位置
httpURLConnection.setRequestProperty("RANGE", "bytes=" + downloadedLength + "-");
// 打开到此 URL 引用的资源的通信链接(如果尚未建立这样的连接)。
httpURLConnection.connect();

(2)在写入数据的时候,调节对应的断点进行结合:

RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
randomAccessFile.seek(downloadedLength);​

方案一:

RandomAccessFile randomAccessFile = new RandomAccessFile(file, “rw”);
randomAccessFile.seek(downloadedLength);

方案二:

FileChannel channelOut = randomAccessFile.getChannel()
MappedByteBuffer mappedBuffer = channelOut.map(FileChannel.MapMode.READ_WRITE,response.body().contentLength());

此处注意的是,在写入数据的时候,有人喜欢用数据通道加缓存来写入数据,这样写的结果其实都是可以的,唯一的区别是用缓存加数据通道(方案二),第一次写入就相当于占用了内存空间,但是实际没有那么大的内存。

(3)在HttpUrlConnection设置对应的下载起点之后,是可以正常下载,但是如果遇到已经下载完的文件,再次点击文件下载,在getInputSteam()方法会IOException.这时候需要判断response返回的code,如果是416那么就返回已经存在的文件就行了。

int code = httpURLConnection.getResponseCode();
if (code == 416) {sendCompletedMsg(createFile(url));return;
}

使用

​HucDownloader.Builder builder = new HucDownloader.Builder()
.url(file_url)
.name("Git.zip")
.folder("Downloader")
.isBreakpoint(true)
.listener(new OnDownloadListener() {@Overridepublic void onDownloading(long total, long progress, int percent) {Log.e("RRL", "onDownloading " + percent);}@Overridepublic void onDownloadCompleted(File file) {Log.e("RRL", "onDownloadCompleted " + file.getAbsolutePath());}@Overridepublic void onDownloadFailed(Exception e) {Log.e("RRL", "onDownloadFailed " + e.toString());}});
downloader = new HucDownloader(builder);
downloader.start();​

源码

(1)HttpsHostnameVerifier

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;/*** Created by Relin* on 2018-11-01.*/
public class HttpsHostnameVerifier implements HostnameVerifier {@Overridepublic boolean verify(String hostname, SSLSession session) {return true;}
}

(2)HttpsX509TrustManager

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;import javax.net.ssl.X509TrustManager;/*** Created by Relin* on 2018-11-01.*/
public class HttpsX509TrustManager implements X509TrustManager{@Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}@Overridepublic void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}@Overridepublic X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0];}
}

(3)HttpsSSLSocketFactory


import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;/*** Created by Relin* on 2018-11-01.*/
public class HttpsSSLSocketFactory {public static SSLSocketFactory factory() {SSLContext sslContext = null;try {sslContext = SSLContext.getInstance("SSL");} catch (NoSuchAlgorithmException e) {e.printStackTrace();}TrustManager[] tm = {new HttpsX509TrustManager()};try {sslContext.init(null, tm, new java.security.SecureRandom());} catch (KeyManagementException e) {e.printStackTrace();}return sslContext.getSocketFactory();}}

(4)HucDownload.java

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;import com.android.image.http.HttpsHostnameVerifier;
import com.android.image.http.HttpsSSLSocketFactory;import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;import javax.net.ssl.HttpsURLConnection;/*** Created by Relin* on 2018/9/19.<br/>* 下载助手可以帮助你简单的调用函数进行下载,同时如果你需要自定义下载网络的方式,<br/>* 只需要继承该类然后重写download方法,在获取到文件流之后调用doHttpResponse()<br/>* 处理对应逻辑就行了。<br/>
* download assistant can help you simply calling a function for download, at the same time,< br / >
*  if you need a custom download network way, < br / >
* only needs to inherit the class and then rewrite the download method,< br / >
*  after the access to file stream call doHttpResponse () < br / >
* handle corresponding logic. < br / >*/
public class HucDownloader {/*** 缓存文件夹*/public static final String CACHE_FOLDER = "Downloader";public static final int WHAT_DOWNLOADING = 0x001;public static final int WHAT_DOWNLOAD_COMPLETED = 0x002;public static final int WHAT_DOWNLOAD_FAILED = 0x003;/*** 总的大小*/private long totalSize = 0;/*** 是否取消*/private boolean isCancel;/*** 是否暂停*/private boolean isPause;/*** 是否在下载中*/private boolean isDownloading;/*** 资源地址*/public final String url;/*** 文件名称*/public final String name;/*** 缓存文件夹*/public final String folder;/*** 实发支持断点下载*/public final boolean isBreakpoint;/*** 下载监听*/public OnDownloadListener onDownloadListener;public HucDownloader(Builder builder) {this.url = builder.url;this.name = builder.name;this.folder = builder.folder;this.isBreakpoint = builder.isBreakpoint;this.onDownloadListener = builder.onDownloadListener;}public static class Builder {private String url;private String name;private String folder;private boolean isBreakpoint;private OnDownloadListener onDownloadListener;public Builder url(String url) {this.url = url;return this;}public Builder name(String name) {this.name = name;return this;}public Builder folder(String folder) {this.folder = folder;return this;}public Builder isBreakpoint(boolean isBreakpoint) {this.isBreakpoint = isBreakpoint;return this;}public Builder listener(OnDownloadListener onDownloadListener) {this.onDownloadListener = onDownloadListener;return this;}public HucDownloader build() {return new HucDownloader(this);}}protected boolean isBreakpoint() {return isBreakpoint;}protected boolean isPause() {return isPause;}protected boolean isCancel() {return isCancel;}protected boolean isDownloading() {return isDownloading;}public void setDownloading(boolean downloading) {this.isDownloading = downloading;}/*** 开始下载*/public void start() {isPause = false;isCancel = false;if (!isDownloading) {download();}}/*** 暂停下载*/public void pause() {isPause = true;}/*** 取消下载*/public void cancel() {isCancel = true;}/*** 销毁下载*/public void destory() {cancel();if (handler != null) {handler.removeCallbacksAndMessages(null);handler = null;}}/*** 创建文件** @param url 资源地址* @return*/protected File createFile(String url) {File cacheFolder = new File(new IOUtils().createFolder(folder == null ? CACHE_FOLDER : folder));if (cacheFolder.isDirectory() && !cacheFolder.exists()) {cacheFolder.mkdirs();}return new File(cacheFolder.getAbsolutePath() + File.separator + (name == null ? createName(url) : name));}/*** 创建Url文件名称** @param url 资源地址* @return*/private String createName(String url) {if (url.contains("/") && url.contains(".")) {return url.substring(url.lastIndexOf("/") + 1);}SimpleDateFormat format = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");return format.format(format) + ".zip";}/*** 下载文件*/private void download() {if (TextUtils.isEmpty(url)) {sendFailedMsg(new IOException("File download network address is empty."));return;}if (!url.toUpperCase().startsWith("HTTP")) {sendFailedMsg(new IOException("File download address error, unable to download normal."));return;}setDownloading(true);download(url);}protected void download(final String url) {new Thread() {@Overridepublic void run() {super.run();try {// 统一资源URL httpUrl = new URL(url);// 连接类的父类,抽象类URLConnection urlConnection = httpUrl.openConnection();// http的连接类HttpURLConnection httpURLConnection = (HttpURLConnection) httpUrl.openConnection();if (url.toUpperCase().startsWith("HTTPS")) {httpURLConnection = (HttpURLConnection) urlConnection;HttpsURLConnection httpsURLConnection = (HttpsURLConnection) httpURLConnection;httpsURLConnection.setHostnameVerifier(new HttpsHostnameVerifier());httpsURLConnection.setSSLSocketFactory(HttpsSSLSocketFactory.factory());httpURLConnection = httpsURLConnection;}httpURLConnection.setDoInput(true);// 设定请求的方法,默认是GEThttpURLConnection.setRequestMethod("GET");// 设置字符编码httpURLConnection.setRequestProperty("Charset", "UTF-8");long downloadedLength = calculateDownloadedLength(url);//设置下载位置httpURLConnection.setRequestProperty("RANGE", "bytes=" + downloadedLength + "-");// 打开到此 URL 引用的资源的通信链接(如果尚未建立这样的连接)。httpURLConnection.connect();int code = httpURLConnection.getResponseCode();if (code == 416) {sendCompletedMsg(createFile(url));return;}// 文件大小int contentLength = httpURLConnection.getContentLength();InputStream is = httpURLConnection.getInputStream();doHttpResponse(is, contentLength, downloadedLength, createFile(url));} catch (MalformedURLException e) {e.printStackTrace();sendFailedMsg(e);} catch (IOException e) {e.printStackTrace();sendFailedMsg(e);}}}.start();}/*** 计算已经下载过的文件大小** @param url* @return*/private long calculateDownloadedLength(String url) {File file = createFile(url);if (file.exists()) {if (isBreakpoint()) {return file.length();} else {file.delete();}}return 0;}/*** 处理服务器返回数据*/protected void doHttpResponse(InputStream is, long contentLength, long downloadedLength, File file) {long downloading = 0;byte[] buf = new byte[2048];int len;RandomAccessFile randomAccessFile = null;try {if (downloadedLength == 0) {totalSize = contentLength;} else {totalSize = downloadedLength + contentLength;}if (totalSize == downloadedLength) {//已下载字节和文件总字节相等,说明下载已经完成了sendCompletedMsg(file);return;}if (totalSize == 0) {if (downloadedLength == 0) {sendFailedMsg(new IOException("The file length value is 0 and cannot be downloaded properly"));} else {if (isBreakpoint()) {sendCompletedMsg(file);} else {file.delete();}}return;}randomAccessFile = new RandomAccessFile(file, "rw");randomAccessFile.seek(downloadedLength);while ((len = is.read(buf)) != -1) {if (isPause() || isCancel()) {break;}randomAccessFile.write(buf, 0, len);downloading += len;long downSum = downloading + downloadedLength;//传递更新信息int percentage = (int) ((downloadedLength + downloading) * 100 / totalSize);sendDownloadingMsg(totalSize, downSum, percentage);}randomAccessFile.close();sendCompletedMsg(file);} catch (Exception e) {sendFailedMsg(e);} finally {setDownloading(false);try {if (is != null)is.close();} catch (IOException e) {sendFailedMsg(e);}try {if (randomAccessFile != null)randomAccessFile.close();} catch (IOException e) {sendFailedMsg(e);}}}/*** 发送成功的信息** @param file*/protected void sendCompletedMsg(File file) {Message msg = handler.obtainMessage();msg.what = WHAT_DOWNLOAD_COMPLETED;msg.obj = file;handler.sendMessage(msg);}/*** 发送下载失败信息** @param e 文件异常*/protected void sendFailedMsg(Exception e) {Message msg = handler.obtainMessage();msg.what = WHAT_DOWNLOAD_FAILED;msg.obj = e;handler.sendMessage(msg);}/*** 发送下载信息** @param total    文件总大小* @param progress 文件进度* @param percent  百分比*/protected void sendDownloadingMsg(long total, long progress, int percent) {Message message = handler.obtainMessage();message.what = WHAT_DOWNLOADING;Bundle bundle = new Bundle();bundle.putLong("total", total);bundle.putLong("progress", progress);bundle.putInt("percent", percent);message.setData(bundle);handler.sendMessage(message);}/*** 下载Handler处理*/private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);if (onDownloadListener == null) {return;}Bundle data = msg.getData();Object obj = msg.obj;switch (msg.what) {case WHAT_DOWNLOADING:onDownloadListener.onDownloading(data.getLong("total"), data.getLong("progress"), data.getInt("percent"));break;case WHAT_DOWNLOAD_COMPLETED:onDownloadListener.onDownloadCompleted((File) obj);break;case WHAT_DOWNLOAD_FAILED:onDownloadListener.onDownloadFailed((Exception) obj);break;}}};}

这篇关于Android HttpUrlConnection 断点下载的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1089469

相关文章

python如何下载网络文件到本地指定文件夹

《python如何下载网络文件到本地指定文件夹》这篇文章主要为大家详细介绍了python如何实现下载网络文件到本地指定文件夹,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下...  在python中下载文件到本地指定文件夹可以通过以下步骤实现,使用requests库处理HTTP请求,并结合o

Android NDK版本迭代与FFmpeg交叉编译完全指南

《AndroidNDK版本迭代与FFmpeg交叉编译完全指南》在Android开发中,使用NDK进行原生代码开发是一项常见需求,特别是当我们需要集成FFmpeg这样的多媒体处理库时,本文将深入分析A... 目录一、android NDK版本迭代分界线二、FFmpeg交叉编译关键注意事项三、完整编译脚本示例四

Android与iOS设备MAC地址生成原理及Java实现详解

《Android与iOS设备MAC地址生成原理及Java实现详解》在无线网络通信中,MAC(MediaAccessControl)地址是设备的唯一网络标识符,本文主要介绍了Android与iOS设备M... 目录引言1. MAC地址基础1.1 MAC地址的组成1.2 MAC地址的分类2. android与I

Android 实现一个隐私弹窗功能

《Android实现一个隐私弹窗功能》:本文主要介绍Android实现一个隐私弹窗功能,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 效果图如下:1. 设置同意、退出、点击用户协议、点击隐私协议的函数参数2. 《用户协议》、《隐私政策》设置成可点击的,且颜色要区分出来res/l

Android实现一键录屏功能(附源码)

《Android实现一键录屏功能(附源码)》在Android5.0及以上版本,系统提供了MediaProjectionAPI,允许应用在用户授权下录制屏幕内容并输出到视频文件,所以本文将基于此实现一个... 目录一、项目介绍二、相关技术与原理三、系统权限与用户授权四、项目架构与流程五、环境配置与依赖六、完整

Android 12解决push framework.jar无法开机的方法小结

《Android12解决pushframework.jar无法开机的方法小结》:本文主要介绍在Android12中解决pushframework.jar无法开机的方法,包括编译指令、框架层和s... 目录1. android 编译指令1.1 framework层的编译指令1.2 替换framework.ja

Android开发环境配置避坑指南

《Android开发环境配置避坑指南》本文主要介绍了Android开发环境配置过程中遇到的问题及解决方案,包括VPN注意事项、工具版本统一、Gerrit邮箱配置、Git拉取和提交代码、MergevsR... 目录网络环境:VPN 注意事项工具版本统一:android Studio & JDKGerrit的邮

Android实现定时任务的几种方式汇总(附源码)

《Android实现定时任务的几种方式汇总(附源码)》在Android应用中,定时任务(ScheduledTask)的需求几乎无处不在:从定时刷新数据、定时备份、定时推送通知,到夜间静默下载、循环执行... 目录一、项目介绍1. 背景与意义二、相关基础知识与系统约束三、方案一:Handler.postDel

Android使用ImageView.ScaleType实现图片的缩放与裁剪功能

《Android使用ImageView.ScaleType实现图片的缩放与裁剪功能》ImageView是最常用的控件之一,它用于展示各种类型的图片,为了能够根据需求调整图片的显示效果,Android提... 目录什么是 ImageView.ScaleType?FIT_XYFIT_STARTFIT_CENTE

Android实现在线预览office文档的示例详解

《Android实现在线预览office文档的示例详解》在移动端展示在线Office文档(如Word、Excel、PPT)是一项常见需求,这篇文章为大家重点介绍了两种方案的实现方法,希望对大家有一定的... 目录一、项目概述二、相关技术知识三、实现思路3.1 方案一:WebView + Office Onl