Android Jetpack 是 Google 推出的一整套帮助 Android 应用程序开发的库、工具包和架构指南,旨在为 Android 应用程序提供更快,更轻松,更稳定的开发体验。自推出以来已经发展成了一个庞大的技术生态系统,包括了许多使用方便、功能强大的库,以下是其中一些新特性、新组件:
-
Paging: 分页库增加了对后端和前端数据的分页处理;
-
Room: 数据库库 Room 的升级增加了对数据库的全面支持和更好的一致性;
-
WorkManager: 工作管理库 WorkManager 更加智能和可靠,支持更复杂的后台任务,并可与后台服务和 Job 统一管理器进行交互;
-
Navigation: 导航库 Navigation 可以更轻松地设置和管理应用程序中的导航功能;
-
CameraX: 相机库 CameraX 简化了相机应用程序的开发;
-
Hilt: 依赖注入库 Hilt 简化了依赖注入和管理;
-
Compose: UI工具包 Compose 提供了更加现代化、灵活和响应式的UI构建方式,可以大大简化UI构建的工作量;
-
AppStartup: App Startup 库提供了对应用程序启动操作的检视和日志记录工具,可以更有效地优化启动时间;
-
Security: 安全库 Security 提供了应用程序安全管理和保护数据的方案。
第五章 CameraX库
-
CameraX 的原理:CameraX 借助 Camera2 API,将相机的各种功能封装成易于使用的 API。同时,他还充分利用了 LiveData 和生命周期等 Android 架构组件,方便地将相机绑定到 UI 组件上。重要的是,CameraX 将为您管理相机使用期间的生命周期,而不是像 Camera1 中那样由您自己管理生命周期。
-
CameraX 的使用场景:CameraX 中的 CameraController 示例是一个简单的相机功能示例,您可以在其中找到一些常见的相机用法:捕获图像、捕获视频以及分析传感器输出,这些示例涵盖相机API上的大部分内容。同时,CameraX 将会在未来支持 AR、扫描等应用。
-
CameraX 相比于之前相机API的优势:CameraX 能够最大程度的降低相机开发的难度,以下为 CameraX 相比之前相机API的优势:
- 易于使用:CameraX 提供易于使用的 API,将拍摄图片和视频的功能封装在一起,并使用 LifeCycleOwner、LiveData 和 ViewModel 等 Android 架构组件与 UI 组件进行高度集成。
- 稳定性高且便于自定义:CameraX 适用于多种设备和操作系统,因为它使用了 Camera2 API 的底层支持,允许您灵活地定制和更改配置,以实现所需的行为。
- 兼容性强:CameraX 兼容 Android 5.0(API 21)及更高版本,并可以与与 Camera2 API 相兼容的所有设备一起使用。
当然,这里为您提供一个完整的 CameraX 相机程序开发的示例代码:
在 build.gradle 文件中添加以下依赖:
dependencies {
def camerax_version = "1.1.0-alpha06"
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
}
在 AndroidManifest.xml 文件中添加相机权限:
<uses-permission android:name="android.permission.CAMERA" />
然后,创建 XML 布局文件 activity_camera.xml,并添加以下代码:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/captureButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_baseline_camera_24"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:backgroundTint="@color/colorPrimary"/>
</FrameLayout>
此布局文件包括 PreviewView 和用于拍照的 FloatingActionButton。使用 FloatingActionButton 组件可作为拍照操作的入口,您可以自定义其样式和行为。
接下来,在 CameraActivity 中,创建 Preview、ImageCapture 和 CameraProvider:
class CameraActivity : AppCompatActivity() {
private lateinit var previewView: PreviewView
private lateinit var captureButton: FloatingActionButton
private lateinit var preview: Preview
private lateinit var imageCapture: ImageCapture
private lateinit var cameraProvider: ProcessCameraProvider
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_camera)
previewView = findViewById(R.id.previewView)
captureButton = findViewById(R.id.captureButton)
preview = Preview.Builder().build()
imageCapture = ImageCapture.Builder().build()
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener(Runnable {
cameraProvider = cameraProviderFuture.get()
bindPreviewUseCase()
}, ContextCompat.getMainExecutor(this))
captureButton.setOnClickListener {
takePhoto()
}
}
override fun onDestroy() {
super.onDestroy()
cameraProvider.unbindAll()
}
private fun bindPreviewUseCase() {
val cameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
val previewUseCase = preview
val imageCaptureUseCase = imageCapture
cameraProvider.bindToLifecycle(this, cameraSelector, previewUseCase, imageCaptureUseCase)
preview.setSurfaceProvider(previewView.surfaceProvider)
}
private fun takePhoto() {
val photoFile = File(externalMediaDirs.first(), "${System.currentTimeMillis()}.jpg")
val metadata = ImageCapture.Metadata().apply {
isReversedHorizontal = CameraSelector.LENS_FACING_BACK == CameraSelector.LENS_FACING_FRONT
}
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(photoFile)
.setMetadata(metadata)
.build()
imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(this),
object : ImageCapture.OnImageSavedCallback {
override fun onError(error: ImageCaptureException) {
error.printStackTrace()
}
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
Toast.makeText(this@CameraActivity, "Photo saved in ${photoFile.absolutePath}",
Toast.LENGTH_LONG).show()
}
})
}
}
如上所述,我们在 onCreate() 方法中创建了 Preview、ImageCapture 和 CameraProvider。然后,使用 ProcessCameraProvider.getInstance() 获取 CameraProvider,并在此处调用 bindPreviewUseCase() 方法,以将 Preview 和 ImageCapture 绑定到相机生命周期。另外,我们通过 takePhoto() 方法以 ImageCapture 输出获取图片,将其保存到文件中,并将其显示在 Toast 栏中。
至此,以上就是 CameraX 相机程序的完整示例代码。