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

相关文章

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

2. 下载rknn-toolkit2项目

官网链接: https://github.com/airockchip/rknn-toolkit2 安装好git:[[1. Git的安装]] 下载项目: git clone https://github.com/airockchip/rknn-toolkit2.git 或者直接去github下载压缩文件,解压即可。

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目