targetSdkVersion > 30 如何将下载的网络视频 保存到手机相册里更新

在 targetSdkVersion 31 中,将下载的网络视频保存到手机相册中涉及几个关键步骤。由于 Android 12(API 级别 31)引入了更多的隐私和安全限制,特别是作用域存储(Scoped Storage),因此你需要遵循这些限制来保存文件。

以下是将下载的网络视频保存到手机相册的步骤:

  1. 请求必要的权限
    • 对于网络下载,你可能需要 INTERNET 权限。
    • 对于保存到外部存储,你需要考虑作用域存储的限制。如果你的应用面向的是 Android 10(API 级别 29)及以上版本,并且你的应用没有声明 requestLegacyExternalStorage 属性为 true,则你需要使用 MediaStore API 来保存文件,并且不需要 WRITE_EXTERNAL_STORAGE 权限。
  2. 下载视频文件
    • 使用适当的网络库(如 OkHttp, Retrofit, Volley 等)从网络下载视频文件。
    • 将下载的视频文件保存到应用的私有目录(例如,使用 getExternalFilesDir(null) 或 getCacheDir())。
  3. 使用 MediaStore 保存视频到相册
    • 创建一个 ContentValues 对象来存储视频文件的元数据。
    • 使用 MediaStore.Video.Media.getExternalContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) 获取外部存储中视频内容的 URI。
    • 调用 ContentResolver.insert() 方法来创建一个新的视频条目。
    • 使用 ContentResolver.openOutputStream() 获取输出流,并将下载的视频文件数据写入该输出流。
  4. 更新媒体数据库
    • 在视频文件写入后,你可能需要通知媒体扫描器扫描该文件,以便它出现在相册中。这可以通过发送一个 Intent 来实现,使用 MediaScannerConnection.SCAN_FILE_ACTION

下面是一个简化的代码示例,展示了如何实现这一过程:

// 假设你已经从网络下载了视频,并且将其保存在了 privateDir 路径下  
File videoFile = new File(privateDir, "downloaded_video.mp4");  // 使用 MediaStore API 保存视频到外部存储  
ContentValues values = new ContentValues();  
values.put(MediaStore.Video.Media.DISPLAY_NAME, videoFile.getName());  
values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");  
values.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES);  Uri collection = MediaStore.Video.Media.getExternalContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);  
Uri videoUri = getContentResolver().insert(collection, values);  try (OutputStream outputStream = getContentResolver().openOutputStream(videoUri)) {  Files.copy(videoFile.toPath(), outputStream);  
} catch (IOException e) {  e.printStackTrace();  
}  // 通知媒体扫描器扫描新文件  
MediaScannerConnection.scanFile(this,  new String[]{videoFile.toString()},  new String[]{"video/*"},  null);

请注意,由于作用域存储的限制,你可能无法直接将文件保存到公共目录(如 Environment.DIRECTORY_MOVIES)。如果你的应用没有请求 MANAGE_EXTERNAL_STORAGE 权限,或者用户没有授予该权限,你可能需要将文件保存到应用的私有目录,并通过 MediaStore 创建一个指向该文件的引用。

此外,始终确保你的应用遵循最新的 Android 存储最佳实践,并考虑到用户隐私和数据安全。

另外

在 Android 10(API 级别 29)及以上版本,由于作用域存储(Scoped Storage)的引入,直接获取文件在外部存储的完整路径变得不再直接可行。相反,您应该使用 ContentResolver 和 ContentValues 将文件保存到 MediaStore,并通过返回的 Uri 来引用它。这样,视频文件就可以被其他应用(如相册)访问,而不需要知道其实际存储路径。

以下是一个示例,展示了如何将下载的视频保存到 MediaStore 并获取其 Uri

private Uri saveVideoToMediaStore(Context context, File videoFile) throws IOException {  // 创建一个 ContentValues 对象来存储视频文件的元数据  ContentValues values = new ContentValues();  values.put(MediaStore.Video.Media.DISPLAY_NAME, videoFile.getName());  values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");  values.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES);  // 获取外部存储中视频内容的 Uri  Uri collection = MediaStore.Video.Media.getExternalContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);  // 使用 ContentResolver 插入一个新的视频条目到 MediaStore  Uri videoUri = context.getContentResolver().insert(collection, values);  // 使用 ContentResolver 打开一个输出流来写入视频文件  try (OutputStream outputStream = context.getContentResolver().openOutputStream(videoUri)) {  Files.copy(videoFile.toPath(), outputStream);  }  // 通知媒体扫描器扫描新文件,使其出现在相册中  MediaScannerConnection.scanFile(context,  new String[]{videoFile.getAbsolutePath()},  new String[]{"video/*"},  null);  return videoUri;  
}

在这个示例中,videoUri 就是您需要的 Uri,它代表了保存在 MediaStore 中的视频文件。您可以使用这个 Uri 来在其他地方引用该视频,例如在一个 Intent 中传递给相册应用。

请注意,由于作用域存储的限制,您无法直接从这个 Uri 获取文件的完整路径。如果您需要这个路径用于某些特定的操作(比如在其他应用中分享文件),您可能需要使用 FileProvider 来创建一个临时访问权限的 Uri

如果您确实需要获取视频文件的路径用于某些特殊情况(比如备份到云存储),您可以使用 ContentResolver 和 openFileDescriptor 方法来获取一个 ParcelFileDescriptor,然后从中获取文件描述符,并最终转换为 File 对象。但请注意,这样做可能会违反 Android 的隐私政策,因此应该谨慎使用,并确保您的应用遵循了所有的最佳实践和隐私指南。

如果您的应用需要兼容低版本的 Android(低于 API 级别 29),您可能需要采用不同的方法来保存视频到外部存储,因为作用域存储(Scoped Storage)在这些版本上不可用。在这种情况下,您可能需要请求 WRITE_EXTERNAL_STORAGE 权限,并将文件直接保存到公共目录(如 /sdcard/DCIM/Camera/)中。

以下是一个兼容低版本的示例,展示如何保存视频到外部存储并获取其路径:

private String saveVideoToExternalStorage(Context context, File videoFile) {  // 确保有写入外部存储的权限  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {  if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)  != PackageManager.PERMISSION_GRANTED) {  // 请求写入外部存储的权限  ActivityCompat.requestPermissions(  (Activity) context,  new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},  MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);  // 等待用户授权  return null;  }  } else {  // 对于低于 Android 10 的版本,您可以在 AndroidManifest.xml 中声明权限  }  // 获取外部存储的目录  File externalStorageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);  if (!externalStorageDir.exists()) {  if (!externalStorageDir.mkdirs()) {  Log.e("VideoSave", "Failed to create directory");  return null;  }  }  // 将视频文件复制到外部存储的目录  File destinationFile = new File(externalStorageDir, videoFile.getName());  try {  Files.copy(videoFile.toPath(), destinationFile.toPath());  return destinationFile.getAbsolutePath();  } catch (IOException e) {  e.printStackTrace();  return null;  }  
}

在这个示例中,我们首先检查应用是否有写入外部存储的权限。如果没有,我们会请求这个权限。一旦获得权限,我们就将视频文件复制到外部存储的 /sdcard/Movies/ 目录下,并返回文件的绝对路径。

请注意,从 Android 10(API 级别 29)开始,推荐的做法是使用 MediaStore API,因为它提供了更好的隐私控制和兼容性。如果您的应用需要支持 Android 10 及更高版本,强烈建议使用 MediaStore 方法。如果您的应用需要兼容低版本,并且您确定您的用户主要使用这些低版本设备,那么您可以使用上述方法。但请记住,随着时间的推移,低版本设备的用户群体可能会逐渐减少,因此最好尽可能使用最新的 API 和实践。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/706657.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java特殊文件、日志技术、多线程

一、属性文件 1.1 特殊文件概述 像这种普通的文本文件,没有任何规律可言,不方便程序对文件中的数据信息处理。 在以后的Java开发过程中还会遇到一些特殊的文本文件,这些文件是有一些格式要求的,方便程序对文件中的数据进行处理。…

机器学习-02-机器学习算法分类以及在各行各业的应用

总结 本系列是机器学习课程的第02篇,主要介绍机器学习算法分类以及在各行各业的应用 本门课程的目标 完成一个特定行业的算法应用全过程: 定义问题(Problem Definition) -> 数据收集(Data Collection) -> 数据分割(Data…

自然语言处理: 第十三章Xinference部署

项目地址: Xorbitsai/inference 理论基础 正如同Xorbits Inference(Xinference)官网介绍是一个性能强大且功能全面的分布式推理框架。可用于大语言模型(LLM),语音识别模型,多模态模型等各种模型的推理。通…

Spring中 Unsupported class file major version 61 报错

初学Spring时遇到的一个错误&#xff1a;Unsupported class file major version 61 &#xff0c;如图所示&#xff1a; 网上查了一下大概是JDK的版本与Spring的版本不一致导致的错误&#xff1b;刚开始我用的Spring版本是&#xff1a; <dependencies><dependency>…

StarRocks实战——多维分析场景与落地实践

目录 一、OLAP 系统历史背景 1.1 历史背景与痛点 1.2 组件诉求 二、StarRocks 的特点和优势 2.1 极致的查询性能 2.2 丰富的导入方式 2.3 StarRocks 的优势特点 三、多维分析的运用场景 3.1 实时计算场景 / 家长监控中心 3.2 实时更新模型选择 3.2.1 更新模型UNIQU…

Eureka简介与使用浅析

Eureka 简介 Eureka 是 Netflix 开发的一款开源服务发现组件&#xff0c;主要用于构建云环境下的微服务架构。它是基于 REST (Representational State Transfer) 的服务&#xff0c;扮演了服务注册与发现的角色&#xff0c;在分布式系统中尤为重要。Eureka Server 作为一个中心…

JDK, JRE, 和 JVM 的解释

在Java编程中&#xff0c;JDK&#xff08;Java Development Kit&#xff0c;Java开发工具包&#xff09;、JRE&#xff08;Java Runtime Environment&#xff0c;Java运行环境&#xff09;和JVM&#xff08;Java Virtual Machine&#xff0c;Java虚拟机&#xff09;是三个核心概…

正则表达式常见的应用场景

数据格式验证&#xff1a;正则表达式可以用来验证输入数据的格式是否符合要求。例如&#xff0c;可以使用正则表达式验证一个邮箱地址是否符合邮箱的格式规范&#xff0c;或者验证一个手机号码是否符合手机号码的格式规范。这在开发网站、手机应用程序等需要用户输入数据的场景…

考研数据结构算法机试训练1

中南大学上机压轴题 测试数据&#xff1a; 3 500 0.6 100 0.8 200 0.7 100 输出 390首先要对输入的折扣进行排序&#xff0c;优先使用比率低的z进行支付。 然后用lowcost记录目前多少钱是打过折的。T-lowcost就是剩余没打折的。 每次循环用上一个人的折扣额度。若所有人折扣额…

2402C++,C++使用单链列表

原文 #include <windows.h> #include <malloc.h> #include <stdio.h>//用于列表项的结构;第一个成员是SLIST_ENTRY结构,其他成员是数据.在此,数据只是测试 typedef struct _PROGRAM_ITEM {SLIST_ENTRY ItemEntry;ULONG Signature; } PROGRAM_ITEM, *PPROGR…

nodejs 实现pdf与图片互转

PDF转图片 效果图 代码 const path require(path); const pdf require(pdf-poppler); const fs require(fs); // PDF文件路径 const pdfFilePath ./path/test.pdf; // 转换选项 const opts { format: png, // 输出图片格式&#xff0c;可以是 jpeg, png, ppm…

3d 舞蹈同步

目录 看起来很强大 unity驱动bvh跳舞&#xff1a; 脚飘动问题&#xff1a; bvh和播放关节对应关系 zxy格式 bvh和播放关节对应关系 zyx的对应关系&#xff1a; bvh播放器&#xff1a; 看起来很强大 GitHub - FORTH-ModelBasedTracker/MocapNET: We present MocapNET, a …

AIGC(生成式人工智能)如何掀起数字化转型的巨浪?

数字化转型已成为当下企业发展的必经之路&#xff0c;而生成式AI作为这场变革的强力引擎&#xff0c;正逐渐展现出其无与伦比的价值。今天&#xff0c;我们将深入探讨生成式AI在日志整理、数据清晰、产品设计等方面的应用&#xff0c;揭示它如何为数字化转型注入强大动力&#…

centos7 无网络安装telnet

一、上传压缩包telnet-20240227.zip并解压 unzip -o telnet-20240227.zip 二、依次安装rpm包 rpm -ivh xinetd-2.3.15.el7.x86_64.rpm rpm -ivh telnet-0.17-65.el7.x86_64.rpm rpm -ivh telnet-server-0.17-65.el7.x86_64.rpm 三、查看是否安装成功 rpm -qa | grep telnet…

数据结构-关键路径

介绍 在AOV网的基础上&#xff0c;如果用对应边来表示活动持续时间&#xff0c;这种有向图被称为AOE网在AOE网中&#xff0c;入度为0的为源点&#xff0c;出度为0的为汇点&#xff0c;整张网看做是一件事情完成的过程&#xff0c;那么这两个点就是事情的开始和结束。每个活动持…

WPF的DataGrid自动生成中文列头

直接将一个对象集合绑定到DataGrid上面&#xff0c;设置自动生成列AutoGenerateColumns"True"&#xff0c;DataGrid会自动根据对象类的属性生成对应的列 示例类对象&#xff1a; public class DataModel{public int Id { get; set; }public string Name { get; set;…

Rocky Linux 运维工具yum

一、yum的简介 ​​yum​是用于在基于RPM包管理系统的包管理工具。用户可以通过 ​yum​来搜索、安装、更新和删除软件包&#xff0c;自动处理依赖关系&#xff0c;方便快捷地管理系统上的软件。 二、yum的参数说明 1、install 用于在系统的上安装一个或多个软件包 2、seach 用…

麒麟银河操作系统V10部署ffmpeg

麒麟银河操作系统V10部署ffmpeg 部署ffmpeg用来处理视频的各种操作 想使用ffmpeg&#xff0c;要先安装nasm&#xff0c;yasm&#xff0c;x264之后&#xff0c;否则会报错 nkvers 查看麒麟操作系统版本 cat /proc/version #查看linux版本信息 uname -a #查看linux版本和内核…

在TMP中计算书名号《》高度的问题

1&#xff09;在TMP中计算书名号《》高度的问题 2&#xff09;FMOD设置中关于Virtual Channel Count&Real Channel Count的参数疑问 3&#xff09;Unity 2021.3.18f1 ParticleSystemTrailGeometryJob粒子拖尾系统崩溃 4&#xff09;XLua打包Lua文件粒度问题 这是第375篇UWA…

数据库管理-第156期 Oracle Vector DB AI-07(20240227)

数据库管理156期 2024-02-27 数据库管理-第156期 Oracle Vector DB & AI-07&#xff08;20240227&#xff09;1 Vector相关DDL操作可以在现有的表上新增vector数据类型的字段&#xff1a;可以删除包含vector数据类型的列&#xff1a;可以使用CTAS的方式&#xff0c;从其他有…