逻辑上是点击自己 Anroid APP 的拍照按钮,然后调用系统内置的相机应用,拍照后,将照片返回给我的 APP。
实际上就是启动一个 activity,并接收其返回的结果数据,然后再处理。
Android 官方推荐使用 AndroidX Activity 和 Fragment 中引入的 Activity Result API,以替代 startActivityForResult() 和 onActivityResult() API。
记录一下实现。
注意,这个方式获取到是图片的缩略图,并不是原始图片的尺寸,而且小非常多,几乎看不清的尺寸,如果要获取原始尺寸,需要参考Android 通过 ACTION_IMAGE_CAPTURE 拍照获取原尺寸的 bitmap 图片
第一步:XML 模板
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:orientation="vertical"
>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
<ImageView
android:id="@+id/imageViewResult"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
<Button
android:id="@+id/btnTakePicture"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/take_picture" />
</LinearLayout>
主要是两部分:
- 按钮:点击触发拍照
- ImageView: 展示拍摄的照片
第二步:Kotlin 实现
class SeedActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_seed)
val launcher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
handleCameraImage(result.data)
}
}
val btnTakePicture = findViewById<Button>(R.id.btnTakePicture)
btnTakePicture.setOnClickListener {
// intent to open camera app
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
launcher.launch(cameraIntent)
}
}
private fun handleCameraImage(intent: Intent?) {
val bitmap = intent?.extras?.get("data") as Bitmap
val imageView = findViewById<ImageView>(R.id.imageViewResult)
imageView.setImageBitmap(bitmap)
}
}
核心是:
- registerForActivityResult: 注册回调逻辑,处理返回的图片
- launch intent: 打开手机摄像头
需要申请的权限
我模拟器里测试,manifest 文件是否配置权限好像都不影响。需要在真机上测试一下。确实需要,可能之前测试有问题。
<uses-feature android:name="android.hardware.camera"
android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- required 可以设置为 false,代表即便没有摄像头也可以用这个 app,但是需要在运行时检测是否有摄像头。
- 要保存完整尺寸的照片,Android 相机应用会保存一张完整尺寸的照片,前提是您为该照片指定了一个文件来保存它。这就需要 WRITE_EXTERNAL_STORAGE 权限。
废弃的方式:startActivityForResult
网上很多实现都是用的 startActivityForResult,甚至《第一行代码 - Android》第三版里也是
private fun dispatchTakePictureIntent() {
val requestImageCapture = 1
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
startActivityForResult(takePictureIntent, requestImageCapture)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
但是,在 Android Studio 里,会提示警告:
'startActivityForResult(Intent!, Int): Unit' is deprecated. Deprecated in Java
即,startActivityForResult 已废弃。
要了解 registerForActivityResult 的使用,详细可以参考我整理的两个例子
是否需要用到 CameraX, Camera2, Camera
从 Android 官方文档看,有三个摄像头相关类库 CameraX, Camera2, Camera。
但是否一定要用那三个库,我看直接用 intent 也行。
https://developer.android.com/training/camerax
CameraX is a Jetpack support library, built to help you make camera app development easier. It provides a consistent and easy-to-use API surface that works across most Android devices, with backward-compatibility to Android 5.0 (API level 21).
While CameraX leverages the capabilities of camera2, it uses a simpler approach that is lifecycle-aware and is based on use cases.
而 Camera 已废弃,所以目前首选是 CameraX。
但是文档看起来非常复杂,我猜测可能是要在自己 APP 内独立实现拍照功能才会用到吧。
如果是未来要实现用摄像头实时分析图片,大概会用到吧。
参考
- 一个完整的流程介绍 https://intensecoder.com/android-open-camera-and-take-picture-in-kotlin
- 官方的文档,用的不是拍照的案例 https://developer.android.com/training/basics/intents/result
- 相对水的一个介绍 https://medium.com/swlh/intro-to-androidx-activity-result-apis-taking-a-picture-6013c3852c0b
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式
谈笑风生
无道 (来自: 中国 四川 成都 电信) 2年前