当前位置: 首页 > 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}}
http://www.lryc.cn/news/503012.html

相关文章:

  • 计算机网络从诞生之初到至今的发展历程
  • Kudu 源码编译-aarch架构 1.17.1版本
  • SEC_ASA 第二天作业
  • 操作系统(5)进程
  • 6_Sass 选择器函数 --[CSS预处理]
  • 考研数学【线性代数基础box(数二)】
  • ModbusTcp获取数据
  • java 知识点:注解及使用
  • AI预测体彩排3采取888=3策略+和值012路+胆码+通杀1码测试12月13日升级新模型预测第156弹
  • faiss数据库检索不稳定
  • Vue技术中参数传递:Props与事件的实践指南
  • C++【基础】 ---- 快速入门 C++
  • Neo4j+Neovis+Vue3:前端连接数据库渲染
  • React 18
  • Java:集合(List、Map、Set)
  • 使用秘钥登录服务器
  • BFS算法题
  • 网络应用技术 实验八:防火墙实现访问控制(华为ensp)
  • 嵌入式现状、机遇、挑战与展望
  • 天通卫星卡通知短信模板
  • Unity WebGL 编译和打包说明(官方文档翻译校正)
  • 题解 - 取数排列
  • JAVA实战:借助阿里云实现短信发送功能
  • 高阶函数:JavaScript 编程中的魔法棒
  • Android 12.0 Launcher3从首页开始安装app功能实现
  • 软考高级架构 - 10.5 软件架构演化评估方法
  • 半导体制造全流程
  • 国科大网络协议安全期末
  • ES动态索引——日志es索引数据按月份存储
  • NLP论文速读(ICML 2024)|面相对齐大语言模型的迁移和合并奖励模型方法