Android使用MediaStore.ACTION_IMAGE_CAPTURE拍照

本文首发地址:https://blog.csdn.net/CSqingchen/article/details/78037071

1. 使用ACTION_IMAGE_CAPTURE,调用系统相机拍摄照片
private fun startTakePhoto() {
    val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    if (intent.resolveActivity(packageManager) != null) {
        val contentValues = ContentValues(2)

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N && false) {
            // 新版本 不一定支持
            contentValues.put(MediaStore.Images.Media.DATA, createImageFile().path)
        } else {
            //拍完保存在Pictures,这里并不需要存储权限,即使拍完读取照片
            contentValues.put(MediaStore.Images.Media.disPLAY_NAME, createImageFileName())
        }

        contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        mPhotoUri = contentResolver.insert(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            contentValues
        )
        intent.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoUri)

        startActivityForResult(intent, CAPTURE_IMG_RQ)
    } else {
        Log.e(TAG, "no activity handle $intent")
    }
}
2. 加载处理拍摄照片结果
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == CAPTURE_IMG_RQ) {
        if (resultCode == RESULT_OK) {
            onImageCaptured()
        } else {
            Log.w(TAG, "on fail:$resultCode")
        }
    }
}

private fun onImageCaptured() {
    val projection = arrayOf(
        MediaStore.MediaColumns._ID,
        MediaStore.Images.ImageColumns.ORIENTATION,
        MediaStore.Images.Media.DATA
    )
    val cursor = contentResolver.query(mPhotoUri!!, projection, null, null, null)
    cursor?.run {
        cursor.movetoFirst()
        try {
            val path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))
            Log.d(TAG, "out file path:$path")
            if (File(path).exists()) {
                Glide.with(this@MainActivity).load(path).into(findViewById(R.id.image_view))

                //也可以直接用上面的Uri
//                    Glide.with(this@MainActivity).load(mPhotoUri).into(findViewById(R.id.image_view))
            }
        } catch (e: Exception) {
            e.printstacktrace()
        }
        cursor.close()
    }
}

如果想采用 ActivityResultContracts.TakePicture 拍摄,可参考后文视频相关代码


3. 拍了一张照片,可是查Media数据库,查不到,可以用如下方法跟新Media数据库查询

调用系统的媒体扫描器,可以将您的照片添加到媒体提供商的数据库中,
使 Android 图库应用中显示这些照片,并使它们可供其他应用使用。

final String[] SCAN_TYPES = {"image/jpeg"};
MediaScannerConnection.scanFile(mContext, new String[]{file.getPath()}, SCAN_TYPES, null);

或者

 Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE).also { mediaScanIntent ->
     mediaScanIntent.data = Uri.fromFile(File(imagePath))
     sendbroadcast(mediaScanIntent)
 }
4. 调用相机 拍摄视频

注意这里会用到 FileProvider 相关知识
AndroidManifest.xml 中需要添加以下内容

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.chenjim.captureintent.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <Meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

res\xml\file_paths.xml内容如下

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <root-path name="root" path="" />
    <files-path name="files" path="files" />
    <cache-path name="cache" path="cache" />
    <external-path name="external" path="external" />
    <external-files-path name="name" path="path" />
    <external-cache-path name="name" path="path" />
</paths>

使用ActivityResultContracts.CaptureVideo拍摄视频

private var mVideoUrl: Uri? = null
private val takeVideo = registerForActivityResult(ActivityResultContracts.CaptureVideo()) { result ->
    if (result == true) {
        Log.d(TAG, "success")
        Glide.with(this@MainActivity).load(mVideoUrl).into(findViewById(R.id.video_view))

        //无法像mPhotoUri 一样通过Uri查询文件路径,如果需要,可以重新导出Uri视频资源
        contentResolver.openInputStream(mVideoUrl!!)?.let { stream ->
            val outFile = File(getExternalFilesDir(null), "capture.video.mp4")
            writeFile(stream, outFile)
            Log.d(TAG, "new out path:$outFile")
        }
    } else {
        Log.d(TAG, "fail")
    }
}
private fun startTakeVideo() {
    val file = File(filesDir, "${SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())}.mp4")
    mVideoUrl = FileProvider.getUriForFile(this, applicationContext.packageName + ".provider", file)
    takeVideo.launch(mVideoUrl)
}

fun writeFile(inputStream: InputStream, out: File) {
    val parentDir = out.parentFile ?: return
    if (!parentDir.exists()) {
        parentDir.mkdirs()
    }
    try {
        FileOutputStream(out).use { fileOutputStream ->
            val buf = ByteArray(1024)
            var length: Int
            while (inputStream.read(buf).also { length = it } != -1) {
                fileOutputStream.write(buf, 0, length)
                fileOutputStream.flush()
            }
            inputStream.close()
            fileOutputStream.flush()
        }
    } catch (e: Exception) {
        Log.e(TAG, out.path + " write fail:" + e)
    }
}

以上示例地址:https://gitee.com/chenjim/CaptureIntent

原创文章,转载请注明出处、原文链接
[email protected] 我的主页 https://chenjim.com


相关文章

相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...