android调用保存相册方法MediaStore.Images.Media.insertImage,部分机型返回null

在使用三星手机时遇到MediaStore.Images.Media.insertImage返回null,导致保存图片失败。问题根源在于缺少WRITE_EXTERNAL_STORAGE权限。通过检查并申请该权限,可以解决部分手机无法保存图片的问题。确保在Android 6.0及以上版本同时请求READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限,避免因权限不足引发的保存错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在调试的时候,使用的模拟器和华为手机均正常保存。用三星的手机时,MediaStore.Images.Media.insertImage返回值为null,保存失败。

解决方案就是:检查权限是否包含了:READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE。由于我写的时候只申请了READ_EXTERNAL_STORAGE权限,没有申请WRITE_EXTERNAL_STORAGE权限,导致部分手机保存失败。

public boolean checkPermissionREAD_EXTERNAL_STORAGE() {
        int currentAPIVersion = Build.VERSION.SDK_INT;
        if (currentAPIVersion >= android.os.Build.VERSION_CODES.M) {
            if (ContextCompat.checkSelfPermission(app,Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
                    ContextCompat.checkSelfPermission(app,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) context,Manifest.permission.READ_EXTERNAL_STORAGE) ||
                        ActivityCompat.shouldShowRequestPermissionRationale((Activity) context,Manifest.permission.WRITE_EXTERNAL_STORAGE)) {    //点击了不再提示
                    this.showAlertDialog("保存失败,请在<设置/权限管理>中开启存储权限后重试!");
                } else {
                    ActivityCompat.requestPermissions(app,new String[] { Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE },MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
                }
                return false;
            } else {
                //成功
                return true;
            }
        } else {
            //成功
            return true;
        }
    }

 

public class VideoUtils { public static void saveVideoToGallery(Context context, File videoFile) { // 创建保存视频的目标路径 File destFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), videoFile.getName()); try { // 复制视频文件到目标路径 copyFile(videoFile, destFile); // 更新媒体库,使其扫描并添加到相册 updateMediaStore(context, destFile); } catch (IOException e) { e.printStackTrace(); } } private static void copyFile(File sourceFile, File destFile) throws IOException { FileChannel sourceChannel = null; FileChannel destChannel = null; try { sourceChannel = new FileInputStream(sourceFile).getChannel(); destChannel = new FileOutputStream(destFile).getChannel(); destChannel.transferFrom(sourceChannel, 0, sourceChannel.size()); } finally { if (sourceChannel != null) { sourceChannel.close(); } if (destChannel != null) { destChannel.close(); } } } private static void updateMediaStore(Context context, File videoFile) { ContentValues values = new ContentValues(); values.put(MediaStore.Video.Media.DATA, videoFile.getAbsolutePath()); values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4"); values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000); Uri uri = context.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values); // 通知媒体库刷新 MediaScannerConnection.scanFile(context, new String[]{videoFile.getAbsolutePath()}, null, null); } }解释这段代码,这段代码是否是插入数据库的方式存储视频数据
最新发布
03-25
<think>好的,我现在要解决的问题是用户询问Java Android中将视频保存至图库的实现原理,以及是否使用数据库操作和MediaStore API。用户还提到给定的代码功能以及是否通过数据库存储视频数据。我需要根据提供的引用内容来回答这些问题。 首先,我需要回忆一下Android保存媒体文件到图库的一般方法。通常,图库中的媒体信息是通过MediaStore数据库管理的,所以可能涉及数据库操作。用户提供的引用中有几处提到图片保存到图库时使用MediaStore API,例如引用[4]中提到了ContentValues和MediaStore.Images.Media的相关字段。这可能说明保存图片时通过MediaStore向系统数据库插入记录,进而让图库显示。同理,保存视频应该也是类似的机制。 接下来,用户的问题是关于视频保存到图库的原理,是否使用数据库操作和MediaStore API。根据引用[4]的内容,保存图片时需要插入正确的字段到MediaStore中,比如DATE_ADDED、SIZE等,并且通过ContentResolver进行插入操作。这说明MediaStore API确实是用来与系统媒体数据库交互的。因此,视频保存应该也是通过MediaStore.Video.Media的API,将视频的信息插入到系统的媒体数据库中,这样图库应用就能扫描到新的视频文件。 然后,关于数据库操作的部分,虽然用户可能认为直接操作SQLite数据库,但实际上Android系统通过MediaStore提供了一层抽象,开发者不需要直接操作数据库,而是通过ContentResolver插入ContentValues到MediaStore的URI中。例如,引用[4]提到使用ContentValues来设置参数,然后调用getContentResolver().insert()方法。这实际上是在向MediaStore数据库添加一条记录,但不需要直接写SQL语句,而是通过API间接操作。 用户还提到是否通过数据库方式存储视频数据。根据引用中的信息,视频文件本身通常是存储在外部存储的公共目录下,例如DCIM、Movies等目录,而MediaStore数据库则存储这些文件的元数据(如路径、大小、时间戳等)。因此,保存视频到图库的过程包括两个步骤:1. 将视频文件保存到正确的目录;2. 通过MediaStore API将视频的元数据插入到系统数据库中,使得图库可以识别和显示该视频。 此外,引用[1]中的代码使用了Intent.ACTION_PICK和MediaStore.Images.Media.EXTERNAL_CONTENT_URI来选择图片,这说明访问图库是通过MediaStore的URI进行的。同理,视频的保存应该会使用MediaStore.Video.Media.EXTERNAL_CONTENT_URI。 在引用[4]中,用户提到时间戳不正确的问题,需要设置正确的ContentValues参数,如DATE_ADDED等。这说明正确的元数据插入是确保视频正确显示在图库中的关键。同样,视频保存时需要设置视频相关的字段,如分辨率、时长等,这些可能通过MediaStore.Video.VideoColumns中的常量来指定。 总结一下,实现原理应该是:使用MediaStore API将视频的元数据插入到系统的媒体数据库中,视频文件保存在公共目录,图库通过查询MediaStore数据库来显示这些视频。而这个过程确实涉及数据库操作,但开发者不需要直接操作数据库,而是通过MediaStore提供的ContentResolver和ContentValues来完成。 至于用户提供的代码是否通过数据库存储视频数据,根据引用中的示例,比如图片保存的代码,视频保存应该也是类似的方式。例如,将视频文件保存到指定目录后,使用MediaStore.Video.Media.insertImage类似的API插入记录。因此,可以确定视频保存到图库的实现原理是基于MediaStore API的数据库操作,但不需要直接处理数据库的SQL语句,而是通过Android提供的API间接操作。</think>在Android中将视频保存至图库的实现原理主要依赖**MediaStore API**,通过向系统媒体数据库插入元数据实现,而非直接操作数据库。以下是具体分析: --- ### **实现原理** 1. **文件存储与元数据插入** - 视频文件需保存到公共目录(如`Movies/`或`DCIM/`),确保图库可扫描到。 - 使用`MediaStore.Video.Media`类构建`ContentValues`对象,设置视频的元数据(如路径、大小、时间戳等)。 - 通过`ContentResolver.insert()`将元数据插入系统媒体数据库,触发图库更新[^4]。 ```java ContentValues values = new ContentValues(); values.put(MediaStore.Video.Media.DISPLAY_NAME, "video.mp4"); values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4"); values.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES); Uri uri = getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values); ``` 2. **MediaStore API的作用** - `MediaStore`是Android提供的系统级媒体数据库,存储所有媒体文件的元数据(如路径、类型、时间戳等)。 - 开发者通过`ContentResolver`间接操作该数据库,无需直接编写SQL语句[^1]。 3. **数据库操作的间接性** - 视频文件本身存储在公共目录,但元数据(如标题、时长、分辨率)通过`MediaStore`插入数据库,供图库应用查询和展示。 --- ### **是否通过数据库操作?** - **是**,但属于**间接操作**。通过`MediaStore API`向系统媒体数据库插入记录,而非直接访问SQLite数据库。例如,设置`ContentValues`字段(如`DATE_TAKEN`、`SIZE`)并调用`insert()`方法,本质是向数据库添加条目。 --- ### **关键代码示例** ```java // 保存视频文件到指定目录,并插入MediaStore数据库 public Uri saveVideoToGallery(Context context, File videoFile) { ContentResolver resolver = context.getContentResolver(); 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); values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000); values.put(MediaStore.Video.Media.SIZE, videoFile.length()); Uri uri = resolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values); try (OutputStream out = resolver.openOutputStream(uri)) { Files.copy(videoFile.toPath(), out); } catch (IOException e) { e.printStackTrace(); return null; } return uri; } ``` --- ### **常见问题与优化** 1. **时间戳错误** - 需正确设置`DATE_ADDED`(单位为秒)和`DATE_TAKEN`(单位为毫秒),避免图库显示异常[^4]。 2. **文件大小计算** - 可通过`File.length()`或预写入`ByteArrayOutputStream`获取准确大小,避免插入无效数据[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值