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

server/2024/12/18 17:58:53/

使用步骤分为两步

okhttp3__1">第一步导入 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}}

http://www.ppmy.cn/server/151231.html

相关文章

Linux安装部署Redis(超级详细)

前言 网上搜索了一筐如何在Linux下安装部署Redis的文章&#xff0c;各种文章混搭在一起勉强安装成功了。自己也记录下&#xff0c;方便后续安装时候有个借鉴之处。 Redis版本 5.0.4服务器版本 Linux CentOS 7.6 64位 下载Redis 进入官网找到下载地址 https://redis.io/down…

Java算法OJ(7)随机快速排序

目录 1.前言 2.正文 1. 快速排序的基本原理 2. 随机快速排序的改进 3. 随机快速排序的步骤 3.小结 1.前言 哈喽大家好吖&#xff0c;今儿给大家带来算法—随机快速排序相关知识点&#xff0c;废话不多说让我们开始。 2.正文 在了解随机快排之前&#xff0c;先了解一下…

<数据集>输电线塔杂物识别数据集<目标检测>

数据集下载链接 &#xff1c;数据集&#xff1e;输电线塔杂物识别数据集&#xff1c;目标检测&#xff1e;https://download.csdn.net/download/qq_53332949/90141102数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;1099张 标注数量(xml文件个数)&#xff1a;1099 …

CTFHub-ssrf

技能树--Web--SSRF 内网访问 开启题目 尝试访问位于127.0.0.1的flag.php吧 进入环境 根据提示输入即可 127.0.0.1/flag.php 伪协议读取文件 开启题目 尝试去读取一下Web目录下的flag.php吧 进入环境&#xff0c;根据提示输入 file:///var/www/html/flag.php 鼠标右键查看…

Hadoop学习

0 小结 一、Hadoop入门 1、常用端口号hadoop3.x HDFS NameNode 内部通常端口&#xff1a;8020/9000/9820HDFS NameNode 对用户的查询端口&#xff1a;9870Yarn查看任务运行情况的&#xff1a;8088历史服务器&#xff1a;19888hadoop2.x HDFS NameNode 内部通常端口&#xff1…

socket服务器多线程优化

在单线程环境下一个线程虽然可以执行任务但是所有的任务都交给一个线程来做当任务积累起来时&#xff0c;前面的任务会影响后续任务的执行&#xff0c;并且现在都是多核处理器我们需要尽可能利用cpu所以多线程 的优化就是一个不错的选择。 我们选择多线程后可以对任务进行分类…

IP数据云查询IP归属地信息

互联网时代&#xff0c;我们每天都会面对大量的网站或App,但你们是否知晓&#xff0c;所有程序员进行程序或者系统的开发都离不开查询IP地址&#xff0c;这是由于对于每个安全的网站/软件来说&#xff0c;基础的服务日志&#xff0c;登录IP等就离不开IP归属地离线库&#xff0c…

如何在服务器上安装 Maven

1. 安装Java Development Kit (JDK) 由于Maven依赖于Java运行环境&#xff0c;因此首先需要确保系统中已经安装了合适的JDK版本。 通过以下命令检查Java版本&#xff0c; java -version如果未安装JDK可以参考如何在服务器上安装 Java OpenJDK相关文档来安装特定版本的JDK。 …