• Android拉起系统相机拍照的两种方式及陷阱


    前言

    在Android中我们可以通过Camera Api在应用内拍照,也可以拉起系统相机进行拍照。拉起系统相机拍照有两种方式。

    Bitmap形式

    这种方式会直接返回Bitmap对象 通过ACTION_IMAGE_CAPTURE这个action调用即可

    var intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    startActivityForResult(intent, code)
    
    • 1
    • 2

    结果处理如下:

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if(requestCode == code && data != null) {
            var bitmap = data?.extras?.get("data") as Bitmap
            imageView.setImageBitmap(bitmap)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在intent中直接返回Bitmap对象,所以我们可以直接进行处理

    文件形式

    这种方式会将图片保存为预定的文件,所以在调用的时候需要传入保存的路径MediaStore.EXTRA_OUTPUT

    var intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        file = File(cacheDir, "2.jpg")
        file?.parentFile?.mkdirs()
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        uri = FileProvider.getUriForFile(this, "包名.fileprovider", file!!)
    }
    else {
        uri = Uri.fromFile(File(Environment.getExternalStorageDirectory(), "1.jpg"))
    }
    intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
    startActivityForResult(intent, code)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这里由于涉及到7.0系统对文件添加了一层安全措施,所以要区别处理。在7.0以下,直接获取uri即可,但是在7.0以上则需要使用FileProvider。

    想要使用FileProvider,上面的代码还不够,我们还需要创建一个xml,在res目录下新建xml目录(如果已有则忽略),在其下新建一个文件file_provider_paths.xml

    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <cache-path
            name="picture"
            path="."/>
    </paths>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    然后在manifest中添加

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="包名.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_provider_paths" />
    </provider>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这里exported和grantUriPermissions是必须的。 然后添加对应的存储权限。

    注意:

    代码中FileProvider.getUriForFile的第二个参数的值要与authorities一样。

    为intent添加一个Intent.FLAG_GRANT_READ_URI_PERMISSION的flag。

    文件的路径要与xml中配置的一致,比如例子中是cache-path,path是"."即本目录,所以代码中的文件路径应该是Context.getCacheDir() + 文件名

    如果是6.0以上手机,还需要进行动态权限申请

    有关FileProvider这里就不细说了.

    结果处理就比较简单,如下:

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if(requestCode == code) {
            var bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)
            //var bitmap = BitmapFactory.decodeFile(file!!.absolutePath)
            imageView.setImageBitmap(bitmap)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    可以通过uri或file两种方式来获取bitmap使用

    通过FileProvider形式拉起相机还需要注意一个问题,在部分手机上外置存储卡的空间不能被应用随意使用。 比如:

    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <external-path
            name="picture"
            path="."/>
    </paths>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    代码中则是:

    file = File(Environment.getExternalStorageDirectory(), "2.jpg")
    file?.mkdirs()
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    uri = FileProvider.getUriForFile(this, "包名.fileprovider", file!!)
    
    • 1
    • 2
    • 3
    • 4

    在部分手机上拉起相机拍照后无法保存到该路径下,所以在处理结果的时候会报FileNotFoundException 或 No such file or directory这种错误。即使允许了存储权限也不可以。

    这种情况就不能使用外置存储,尽量使用应用本身的存储空间,比如例子中的CacheDir

    关注公众号:BennuCTech,获取更多干货!

  • 相关阅读:
    5个实用的SQLite数据库可视化工具(GUI)
    WPF 截图控件之绘制箭头(五)「仿微信」
    【ML】Q-Learning应用于具有连续状态的问题(Q-Learning 学习滑冰)
    vue水波纹指令
    Vue3--Vue Router详解--学习笔记
    关于Java并发多线程的一点思考
    ElasticSearch学习笔记:内容有点多,但很实用(包含安装、使用、安全、部署)
    Python循环结构详解
    通过实战操作学git
    wget什么意思
  • 原文地址:https://blog.csdn.net/chzphoenix/article/details/122696572