将媒体文件路径或 URI 保存到 SQLite 并获取它,最佳实践

如何解决将媒体文件路径或 URI 保存到 SQLite 并获取它,最佳实践

我的目标是:

  • 将媒体文件保存到外部存储(在我的例子中是照片)。
  • 获取已保存数据的文件路径或 URI。
  • 将其保存到 SQLite(文件路径或内容 URI 或其他)。
  • 能够在未来的任何时候获得此内容的正确 URI。

它与其他非常流行的应用程序所做的非常相似 - 他们在“图片”文件夹中创建他们的目录,并将照片存储在那里,并在他们的应用程序中使用它们,同时还可以使用图库/文件浏览器等查看它们。

>

据我所知,保存媒体内容(图像,f.e.)的推荐方法是使用 MediaStore API,因此我获得了内容 URI,以后可以使用。 但是后来我读到这些内容 URI 在重新扫描媒体后可能会更改,因此它看起来不可靠。 (例如如果使用了 SD 卡,然后将其取出并重新插入)

同时,不推荐使用绝对文件路径,并且倾向于弃用使用绝对文件路径来处理外部存储的 API。所以看起来也不靠谱。

我只能想象以下解决方案:

  • 保存时使用唯一的自动生成的文件名(如 UUID)。
  • 当我需要获取内容 URI 时(例如想要在 ImageView 中渲染照片)- 我可以使用 ContentResolver 并使用文件名过滤器搜索内容 URI。

这种方法的问题是我有很多照片(图库),使用 ContentResolver 查询它会显着影响性能。

我觉得我把事情复杂化了,错过了一些东西。

解决方法

你确实把事情复杂化了。 将文件存储到文件系统中所需的文件夹中(最好将文件夹命名为您的应用程序名称)

存储此路径或 URI 路径 - 无论您喜欢什么。 (不要在您的应用中对传递进行硬编码 - 设备供应商在他们的设备中可能有不同的基本路径)

只要文件夹的名称相同并且其中的文件名称相同(与您的数据库中的名称相同) - 即使取出 SD 卡然后重新放入,您也可以访问它们。

重新索引后可能会出现并发症 - 但在我作为 Android 开发人员工作的八年中,我只遇到过一次,因此您可以轻松忽略这些东西。

如果您想对存储的内容有更多的控制权并希望限制对其的访问 - 将数据存储到应用程序的内部存储中 - 这样您就可以 100% 确定数据在哪里,它不在被篡改。

从 Android 10 开始,您有范围存储 - 它就像内部存储,但它甚至可能位于外部 sdcard 上。

Here 是可能的存储位置的简要概述。

不要想太多 - 它是手机的默认用例,它的工作原理与您预期的一样 - 非常好且非常稳定。

,

我建议您使用 Intent.ACTION_OPEN_DOCUMENT 来满足您的需求。

1.创建照片挑选Intent

val REQUEST_CODE_PICK_PHOTO = 1

fun pickAndSavePhoto(requestCode: Int) {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)

    intent.type = "image/*"

    startActivityForResult(intent,requestCode)
}

2.处理结果:

override fun onActivityResult(requestCode: Int,resultCode: Int,data: Intent?) {
    super.onActivityResult(requestCode,resultCode,data)

    if (requestCode == REQUEST_CODE_PICK_PHOTO && resultCode == RESULT_OK) {
        val imageUri = data!!.data!!

        //save this uri to your database as String -> imageUri.toString()
    }
}

3.取回图像并在 ImageView 上显示:

fun getBitmapFromUri(context: Context,imageUri: Uri): Bitmap? {  //uri is just an address,image may be deleted any time,if so returns null
    val bitmap: Bitmap

    return try {
        val inputStream = context.contentResolver.openInputStream(imageUri)

        inputStream.use {
            bitmap = BitmapFactory.decodeStream(it)
        }

        bitmap
    } catch (e: Exception) {
        Log.e("getBitmapFromUri()","Image not found.")

        null
    }
}

val bitmap = getBitmapFromUri(context,imageUri)  //get uri String from database and convert it to uri -> uriString.toUri()

if (bitmap != null) {
    imageView.setImageBitmap(bitmap)
}
,

首先需要在manifest和Runtime Permission中申请外部存储权限。

在此目录中创建用于保存图像的目录之后。

您还必须在 XML 和代码端添加文件提供程序,因为它是必需的。

现在是时候检查我的代码以将图像保存在文件夹中以及图库中的这些图像并从文件路径中获取路径。

    • 将 URI 转换为位图

http://prntscr.com/10dpvjj

    • 获取位图保存图像功能

    private String save(Bitmap bitmap) {

     File save_path = null;
        if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
            try {
                File sdCard = Environment.getExternalStorageDirectory();
                File dir = new File(sdCard.getAbsolutePath() + "/SaveDirectory");
                dir.mkdirs();
                File file = new File(dir,"DirName_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().getTime()) + ".png");
                save_path = file;
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.PNG,100,baos);
                FileOutputStream f = null;
                f = new FileOutputStream(file);
                MediaScannerConnection.scanFile(context,new String[]{file.getAbsolutePath()},null,null);
                if (f != null) {
                    f.write(baos.toByteArray());
                    f.flush();
                    f.close();
                }
             } catch (Exception e) {
                 // TODO: handle exception
             }
             Share(save_path); // call your Function Store into database
             Log.e("PathOFExec----","save: " + save_path);
         }
    
    • 如果您愿意,可以将存储图像位置添加到您的数据库中

    private void Share(File savePath) {

     if (savePath != null) {
    
         Uri uri = FileProvider.getUriForFile(context,context.getApplicationContext().getPackageName() + ".provider",savePath);
    
         Intent share = new Intent(Intent.ACTION_SEND);
         share.setType("image/*");
         share.putExtra(Intent.EXTRA_TEXT,"TextDetail");
         share.putExtra(Intent.EXTRA_STREAM,uri);
         context.startActivity(Intent.createChooser(share,"Share Image!"));
    
     //after getting URI you can store the image into SQLite databse for get uri
    
     }
    

    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-