当前位置: 首页 > news >正文

Android通过okhttp下载文件(本文案例 下载mp4到本地,并更新到相册)

使用步骤分为两步

第一步导入 okhttp3 依赖

第二步调用本文提供的 utils

第一步这里不做说明了,直接提供第二步复制即用

在这里插入图片描述

DownloadUtil 中 download 为下载文件 参数说明

在这里插入图片描述
这里主要看你把 destFileName 下载文件名称定义为什么后缀,比如我定义为 .mp4 下载后 就是 mp4 格式

这里 destFileDir 下载目录要说一下,如果没有开启存储权限或者使用了系统默认路径就会报错 比如 /0 文件一类的错误,怎么使用可以参考 open failed: ENOENT (No such file or directory) 解决办法

DownloadUtil 中 saveVideoToAlbum 为将下载好的视频更新到手机图库中,原来的放式已经随着安全性提高不适用了,这里基本就是复制出一份更新到系统层的文件夹

源码

DownloadUtil.download(mVideoUrl,getUrlPath(),"sing示例名称${System.currentTimeMillis()}.mp4",object : DownloadUtil.OnDownloadListener{override fun onDownloadSuccess(file: File?) {"下载成功".toast()//更新视频到相册DownloadUtil.saveVideoToAlbum(this@MoreActivity,file?.absolutePath)Log.e("视频下载", "下载成功: ${file?.absolutePath}")}override fun onDownloading(progress: Int) {Log.e("视频下载", "下载进度:${progress}")}override fun onDownloadFailed(e: Exception?) {LoadingSingDialog.dismiss()Log.e("视频下载", "下载失败:${e?.printStackTrace()}")}})

DownloadUtil

object DownloadUtil {private var okHttpClient: OkHttpClient? = null/*** @param url          下载连接* @param destFileDir  下载的文件储存目录* @param destFileName 下载文件名称* @param listener     下载监听*/fun download(url: String, destFileDir: String, destFileName: String, listener: OnDownloadListener) {if (url == null || url == ""){return}if (okHttpClient == null){okHttpClient = OkHttpClient()}val request: Request = Request.Builder().url(url).build()okHttpClient!!.newCall(request).enqueue(object : Callback {override fun onFailure(call: Call, e: IOException) {// 下载失败监听回调listener.onDownloadFailed(e)}@Throws(IOException::class)override fun onResponse(call: Call, response: Response) {if (response.body != null) {var inputStream: InputStream? = nullval buf = ByteArray(2048)var len = 0var fos: FileOutputStream? = null// 储存下载文件的目录val dir = File(destFileDir)if (!dir.exists()) {dir.mkdirs()}val file = File(dir, destFileName)try {inputStream = response.body!!.byteStream()val total: Long = response.body!!.contentLength()fos = FileOutputStream(file)var sum: Long = 0while (inputStream.read(buf).also { len = it } != -1) {fos.write(buf, 0, len)sum += len.toLong()val progress = (sum * 1.0f / total * 100).toInt()// 下载中更新进度条listener.onDownloading(progress)}fos.flush()// 下载完成listener.onDownloadSuccess(file)} catch (e: Exception) {listener.onDownloadFailed(e)} finally {try {inputStream?.close()} catch (e: IOException) {listener.onDownloadFailed(e)}try {fos?.close()} catch (e: IOException) {listener.onDownloadFailed(e)}}}else{listener.onDownloadFailed(IOException("接口失败"))}}})}interface OnDownloadListener {/*** @param file 下载成功后的文件*/fun onDownloadSuccess(file: File?)/*** @param progress 下载进度*/fun onDownloading(progress: Int)/*** @param e 下载异常信息*/fun onDownloadFailed(e: Exception?)}/*** 将视频保存到系统相册*/fun saveVideoToAlbum(context: Context, videoFile: String?): Boolean {if (videoFile == null || videoFile == ""){return false}return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {saveVideoToAlbumBeforeQ(context, videoFile)} else {saveVideoToAlbumAfterQ(context, videoFile)}}private fun saveVideoToAlbumAfterQ(context: Context, videoFile: String): Boolean {return try {val contentResolver = context.contentResolverval tempFile = File(videoFile)val contentValues = getVideoContentValues(context, tempFile, System.currentTimeMillis())val uri =contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues)copyFileAfterQ(context, contentResolver, tempFile, uri)contentValues.clear()contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)context.contentResolver.update(uri!!, contentValues, null, null)context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri))true} catch (e: java.lang.Exception) {e.printStackTrace()false}}private fun saveVideoToAlbumBeforeQ(context: Context, videoFile: String): Boolean {val picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)val tempFile = File(videoFile)val destFile = File(picDir, context.packageName + File.separator + tempFile.name)var ins: FileInputStream? = nullvar ous: BufferedOutputStream? = nullreturn try {ins = FileInputStream(tempFile)ous = BufferedOutputStream(FileOutputStream(destFile))var nread = 0Lval buf = ByteArray(1024)var n: Intwhile (ins.read(buf).also { n = it } > 0) {ous.write(buf, 0, n)nread += n.toLong()}MediaScannerConnection.scanFile(context, arrayOf(destFile.absolutePath), arrayOf("video/*")) { path: String?, uri: Uri? -> }true} catch (e: java.lang.Exception) {e.printStackTrace()false} finally {try {ins?.close()ous?.close()} catch (e: IOException) {e.printStackTrace()}}}@Throws(IOException::class)private fun copyFileAfterQ(context: Context,localContentResolver: ContentResolver,tempFile: File,localUri: Uri?) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&context.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {//拷贝文件到相册的uri,android10及以上得这么干,否则不会显示。可以参考ScreenMediaRecorder的save方法val os = localContentResolver.openOutputStream(localUri!!)Files.copy(tempFile.toPath(), os)os!!.close()tempFile.delete()}}/*** 获取视频的contentValue*/private fun getVideoContentValues(context: Context, paramFile: File, timestamp: Long): ContentValues {val localContentValues = ContentValues()if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {localContentValues.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM+ File.separator + context.packageName)}localContentValues.put(MediaStore.Video.Media.TITLE, paramFile.name)localContentValues.put(MediaStore.Video.Media.DISPLAY_NAME, paramFile.name)localContentValues.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")localContentValues.put(MediaStore.Video.Media.DATE_TAKEN, timestamp)localContentValues.put(MediaStore.Video.Media.DATE_MODIFIED, timestamp)localContentValues.put(MediaStore.Video.Media.DATE_ADDED, timestamp)localContentValues.put(MediaStore.Video.Media.SIZE, paramFile.length())return localContentValues}}

相关文章:

Android通过okhttp下载文件(本文案例 下载mp4到本地,并更新到相册)

使用步骤分为两步 第一步导入 okhttp3 依赖 第二步调用本文提供的 utils 第一步这里不做说明了&#xff0c;直接提供第二步复制即用 DownloadUtil 中 download 为下载文件 参数说明 这里主要看你把 destFileName 下载文件名称定义为什么后缀&#xff0c;比如我定义为 .mp4 下…...

计算机网络从诞生之初到至今的发展历程

前言 "上网"&#xff0c;相信大家对这个动词已经不再陌生&#xff0c;网 通常指的是网络&#xff1b;在 2024 年的今天&#xff0c;网络已经渗透到了每个人的生活中&#xff0c;成为其不可或缺的一部分&#xff1b;你此时此刻在看到我的博客&#xff0c;就是通过网络…...

Kudu 源码编译-aarch架构 1.17.1版本

跟着官方文档编译 第一个问题&#xff1a;在make阶段时会报的问题&#xff1a; kudu/src/kudu/util/block_bloom_filter.cc:210:3: error: ‘vst1q_u32_x2’ was not declared in this scope kudu/src/kudu/util/block_bloom_filter.cc:436:5: error: ‘vst1q_u8_x2’ was no…...

SEC_ASA 第二天作业

拓扑 按照拓扑图配置 NTP&#xff0c;Server端为 Outside路由器&#xff0c;Client端为 ASA&#xff0c;两个设备的 NTP传输使用MD5做校验。&#xff08;安全 V4 LAB考点&#xff09; 提示&#xff1a;Outside路由器作为 Server端要配置好正确的时间和时区&#xff0c;ASA防…...

操作系统(5)进程

一、定义与特点 定义&#xff1a;进程是计算机中的程序关于某数据集合上的一次运行活动&#xff0c;是系统进行资源分配和调度的基本单位&#xff0c;是操作系统结构的基础。 特点&#xff1a; 动态性&#xff1a;进程是动态创建的&#xff0c;有它自身的生命周期&#xff0c;…...

6_Sass 选择器函数 --[CSS预处理]

Sass 提供了一系列的选择器函数&#xff0c;用于操作和组合CSS选择器。这些函数可以帮助你更灵活地创建样式规则&#xff0c;并且可以减少重复代码。以下是几个常用的选择器函数及其用法&#xff1a; 1. selector-append($selector1, $selector2...) selector-append($select…...

考研数学【线性代数基础box(数二)】

本文是对数学二线性代数基础进行总结&#xff0c;一些及极其简单的被省略了&#xff0c;代数的概念稀碎&#xff0c;不如高数关联性高&#xff0c;所以本文仅供参考&#xff0c;做题请从中筛选&#xff01; 本文为初稿&#xff0c;后面会根据刷题和自己的理解继续更新 第一章…...

ModbusTcp获取数据

ModbusTcp获取数据 记录一个用 pymodbus 库来获取数据的代码。 注意&#xff1a; 1.读取寄存器地址是16进制的。2.大小端转换通过代码知道原理。读取数据时&#xff0c;切记频率别太高&#xff0c;否则会出现连接被关闭问题。 from pymodbus.client.sync import ModbusTcpCli…...

java 知识点:注解及使用

注解 大多数时候&#xff0c;我们会使用注解&#xff0c;而不是自定义注解。注解给谁用&#xff1f;编译器 、给解析程序用注解不是程序的一部分&#xff0c;可以理解为注解就是一个标签 主要的作用有以下四方面&#xff1a; 生成文档&#xff0c;通过代码里标识的元数据生成…...

AI预测体彩排3采取888=3策略+和值012路+胆码+通杀1码测试12月13日升级新模型预测第156弹

经过100多期的测试&#xff0c;当然有很多彩友也一直在观察我每天发的预测结果&#xff0c;得到了一个非常有价值的信息&#xff0c;那就是9码定位的命中率非常高&#xff0c;已到达90%的命中率&#xff0c;这给喜欢打私菜的朋友提供了极高价值的预测结果~当然了&#xff0c;大…...

faiss数据库检索不稳定

faiss数据检索不稳定 def build_faiss_index(embeddings_vector):dim np.shape(embeddings_vector)[-1]index faiss.index_factory(dim, HNSW64, faiss.METRIC_INNER_PRODUCT)index.add(embeddings_vector)return index这个代码不稳定&#xff0c;构建的索引召回结果可能会不…...

Vue技术中参数传递:Props与事件的实践指南

在Vue.js中&#xff0c;组件间的参数传递是构建动态和交互式应用的核心。本文将深入探讨如何通过Props和事件&#xff08;$emit&#xff09;在Vue组件间进行参数传递&#xff0c;并提供代码示例。 Props传递数据 Props是Vue中组件间传递数据的一种方式&#xff0c;它允许父组…...

C++【基础】 ---- 快速入门 C++

文章目录 前言一、有关 const 区分二、有关命名空间三、有关输入和输出四、有关缺省参数四、函数重载总结 前言 本篇文章笔者将会对 C 这么语言中必须的基础部分进行简单讲解 , 同时也作为笔者自我复习使用, 这部分是初学C 的学者不可绕过的部分 , 希望学者认真理解 ,认真领会…...

Neo4j+Neovis+Vue3:前端连接数据库渲染

Neovis&#xff08;github&#xff09;&#xff1a;https://github.com/neo4j-contrib/neovis.js Neovis配置文档&#xff1a;neovis.js (neo4j-contrib.github.io) 一、安装Neo4j 参考文章&#xff1a;neo4j下载安装配置步骤-CSDN博客 二、Neovis使用 1.npm引入 ?npm ins…...

React 18

文章目录 React 18自动批处理并发特性Suspense 组件增强新 HookscreateRoot API 替代 ReactDOM.renderStrict Mode严格模式服务器端渲染改进性能优化 React 18 React 18 引入了一系列新特性和改进&#xff0c;旨在提升性能、改善用户体验&#xff0c;并简化开发流程。以下是 R…...

Java:集合(List、Map、Set)

文章目录 1. Collection集合1-1. 迭代器遍历方式1-2. 通过for循环进行遍历1-3. forEach遍历 2. List集合2-1. ArrayList底层实现原理2-2. LinkedList底层实现原理 3. Set集合3-1. HashSet 底层实现3-2. LinkedHashSet 底层实现3-3. TreeSet 4. Collection集合->总结5. Map集…...

使用秘钥登录服务器

在我们测试或生产环境中&#xff0c;为了服务器安全性&#xff0c;有时可能需要以 SSH 密钥的方式登录服务器&#xff0c;接下来&#xff0c;将演示如何通过 SSH 私钥的方式来远程服务器。 一、远程服务器生成密钥对 1、首先在目标远程服务器下生成 SSH 密钥对 ssh-keygen然…...

BFS算法题

目录 1.BFS 2.树里的宽搜 题目一——429. N 叉树的层序遍历 - 力扣&#xff08;LeetCode&#xff09; 题目二——103. 二叉树的锯齿形层序遍历 - 力扣&#xff08;LeetCode&#xff09; 题目三——662. 二叉树最大宽度 - 力扣&#xff08;LeetCode&#xff09; 题目四——…...

网络应用技术 实验八:防火墙实现访问控制(华为ensp)

目录 一、实验简介 二、实验目的 三、实验需求 四、实验拓扑 五、实验步骤 1、设计全网 IP 地址 2、设计防火墙安全策略 3、在 eNSP 中部署园区网 4、配置用户主机地址 5、配置网络设备 配置交换机SW-1~SW-5 配置路由交换机RS-1~RS-5 配置路由器R-1~R-3 6、配置仿…...

嵌入式现状、机遇、挑战与展望

在当今数字化浪潮中&#xff0c;嵌入式系统宛如一颗璀璨的明珠&#xff0c;熠熠生辉&#xff0c;深刻地渗透到了我们生活的方方面面&#xff0c;成为推动现代科技进步不可或缺的关键力量。从智能家居的便捷控制&#xff0c;到工业生产的精准运作&#xff0c;再到汽车的智能驾驶…...

天通卫星卡通知短信模板

文章目录 引言I 阿里云新增短信模板短信模板通知短信变量规范计费规则: 短信长度不超过70个字,按照1条短信计费;II 表设计III 实现方案引言 背景:天通卡适用于应急救灾、登山探险、海上通信、野外作业等需要稳定可靠通信的场景。 需求:天通卡充值成功通知 平台基于阿里云给…...

Unity WebGL 编译和打包说明(官方文档翻译校正)

目录 Unity WebGL 编译和打包说明WebGL 简介WebGL 浏览器兼容性 (WebGL Browser Compatibility)平台支持 (Platform Support)多线程支持限制多线程支持的因素安装 Unity Hub 并添加所需模块WebGL 开发WebGL Player 设置Resolution and PresentationResolutionWebGL TemplateSpl…...

题解 - 取数排列

题目描述 取1到N共N个连续的数字&#xff08;1≤N≤9&#xff09;&#xff0c;组成每位数不重复的所有可能的N位数&#xff0c;按从小到大的顺序进行编号。当输入一个编号M时&#xff0c;就能打印出与该编号对应的那个N位数。例如&#xff0c;当N&#xff1d;3时&#xff0c;可…...

JAVA实战:借助阿里云实现短信发送功能

亲爱的小伙伴们&#x1f618;&#xff0c;在求知的漫漫旅途中&#xff0c;若你对深度学习的奥秘、JAVA 、PYTHON与SAP 的奇妙世界&#xff0c;亦或是读研论文的撰写攻略有所探寻&#x1f9d0;&#xff0c;那不妨给我一个小小的关注吧&#x1f970;。我会精心筹备&#xff0c;在…...

高阶函数:JavaScript 编程中的魔法棒

在JavaScript的世界里&#xff0c;高阶函数是一种强大的工具&#xff0c;它允许我们将函数作为参数传递或将函数作为返回值。这种特性使得JavaScript代码更加灵活和强大。本文将深入探讨高阶函数的定义、用法以及在实际项目中的最佳实践&#xff0c;帮助大家更好地理解和应用这…...

Android 12.0 Launcher3从首页开始安装app功能实现

1.前言 在12.0的系统rom定制化开发中,在进行Launcher3的某些功能开发实现过程中,在某些项目中,安装的app比较多,要求在launcher3的首页开始安装 app应用,接下来就需要分析下app安装图标排序的流程,然后在实现相关的功能 2. Launcher3从首页开始安装app功能实现的核心…...

软考高级架构 - 10.5 软件架构演化评估方法

10.4 软件架构演化原则总结 本节提出了18条架构演化的核心原则&#xff0c;并为每条原则设计了简单而有效的度量方法&#xff0c;用于从系统整体层面提供实用信息&#xff0c;帮助评估和指导架构演化。 演化成本控制&#xff1a;成本小于重新开发成本&#xff0c;经济高效。进…...

半导体制造全流程

半导体制造是一个极其复杂且精密的过程&#xff0c;主要涉及将硅片加工成功能强大的芯片。以下是半导体制造的全流程概述&#xff1a; 1. 硅材料制备 硅提纯&#xff1a; 使用冶金级硅&#xff0c;进一步提纯为高纯度硅&#xff08;电子级硅&#xff09;&#xff0c;纯度可达 …...

国科大网络协议安全期末

完整资料仓库地址&#xff1a;https://gitee.com/etsuyou/UCAS-Network-Protocol-Security 部分题目&#xff1a; 六 论述题10*220 试讨论IPv6解决了IPv4的哪些“痛点”&#xff0c;以及IPv6存在的安全问题试比较IPsec与SSL的安全性 五 简答题5*315 简述MAC欺骗和ARP欺骗的…...

ES动态索引——日志es索引数据按月份存储

一、定义ES索引 NoArgsConstructor AllArgsConstructor Data Accessors(chain true) Document(indexName "charge_pile_log" Constants.ES_TIME_DYNAMIC_INDEX) //(索引名称动态&#xff0c;前面固定&#xff0c;后面月份) public class ChargePileLogESDomain {…...

求网站建设/雅虎搜索

本文实例讲述了Python实现PS滤镜Fish lens图像扭曲效果。分享给大家供大家参考&#xff0c;具体如下&#xff1a;这里实现 PS 滤镜中的一种几何变换– Fish lens&#xff0c; 对图像做扭曲&#xff0c;感觉就像通过一个凸镜或者凹镜在观察图像一样。import numpy as npfrom ski…...

wordpress后台语言设置/深圳搜索引擎优化推广便宜

1:什么是同步队列&#xff08;CLH&#xff09; 同步队列 一个FIFO双向队列&#xff0c;队列中每个节点等待前驱节点释放共享状态&#xff08;锁&#xff09;被唤醒就可以了。 AQS如何使用它&#xff1f; AQS依赖它来完成同步状态的管理&#xff0c;当前线程如果获取同步状态…...

南通网站推广公司/抖音seo排名系统

能用通俗的语言解释下DSP和DMP的广告吗&#xff1f; 本人广告小白一枚&#xff0c;网上也看了些DSP和DMP的介绍&#xff0c;依然很难理解它的操作模式&#xff0c;能用通俗的语言解释下DSP和DMP的广告DSP只是广告发布的技术平台&#xff0c;不是媒体。你可以理解成是一个电视广…...

网站建设的后台登录/外贸如何做网站推广

应用介绍◎◎◎◎〖内容提要〗◎◎◎◎搜狗地图&#xff0c;一个能语音与你交流并解决问题的车内助手&#xff0c;彻底解放手眼&#xff0c;行车更安全&#xff1b;浏览地图、出行导航、搜索地点&#xff0c;线路查询、离线下载&#xff0c;一步到位&#xff1b;⊙AR实景导航&a…...

专题页是什么/泰州seo外包公司

本系列笔记主要是回顾了一下PHP中和日期操作相关的函数在PHP中设置时区有三种方法&#xff1a;1、直接在php的配置文件中修改以mac系统为例&#xff0c;我使用的是mamp pro 集成环境&#xff0c;所以我就说明了一下如何修改这种环境下的配置文件。a) 打开终端&#xff0c;输入 …...

在网站留外链怎么做/许昌seo公司

场景&#xff1a;多个相同的Windows服务(部署在不同的服务器上&#xff0c; 仅配置文件不同)需要附加WCF服务&#xff0c; 而网站在访问这些类似的WCF服务时&#xff0c; 不知道其明确地址所以无法直接引用。于是&#xff0c; 无配置便成了必然的选择&#xff01; 下面是无配置…...