Android使用MediaStore.ACTION_IMAGE_CAPTURE拍照
本文首发地址 https://h89.cn/archives/187.html
最新更新地址 https://gitee.com/chenjim/chenjimblog
本文示例地址 https://gitee.com/chenjim/CaptureIntent
用 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")
}
}
以上在 MIUI 验证通过,若其它手机存在异常,欢迎留言讨论。
这里是否可以调用三方相机,比如美图秀秀呢?
在 美图秀秀 安卓应用 AndroidManifest.xml 中,我们可以看到如下配置,也就是支持其它应用调用的
<activity android:name="com.mt.mtxx.camera.view.CameraActivity">
<intent-filter>
<action android:name="android.media.action.IMAGE_CAPTURE"/>
<action android:name="com.meitu.ble.intent.capture_with_rc"/>
<action android:name="com.meitu.mtxx.action.image_capture"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
但是从安卓 11 开始,无法调用三方相机(比如美图秀秀)拍摄,具体可以参见 博文
加载拍摄照片
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 拍摄,可参考后文拍摄视频相关代码
用 ActivityResultContracts 拍摄视频
注意这里会用到 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)
}
}
常见问题及处理
- 拍了一张照片,查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) }
相关文章
本文链接:Android使用MediaStore.ACTION_IMAGE_CAPTURE拍照 - https://h89.cn/archives/187.html
版权声明:原创文章 遵循 CC 4.0 BY-SA 版权协议,转载请附上原文链接和本声明。