1. CameraX 最小预览

CameraX 最小预览 学习卡片

最小预览的组成与生命周期

CameraX 最小预览由四个对象协作完成:PreviewView 负责显示画面,Preview 用例负责从相机取流,ProcessCameraProvider 负责把用例绑定到相机,CameraSelector 决定使用哪颗镜头。绑定发生在 onCreate 之后、界面可见之前;解绑由 LifecycleOwner 自动完成,无需手动调用 unbind。

Activity 生命周期 onCreate onStart onResume(可见) onPause onDestroy CameraX 核心对象 PreviewView SurfaceProvider 提供显示面 Preview 用例 setSurfaceProvider(previewView) ProcessCameraProvider bindToLifecycle(owner, selector, preview) CameraSelector DEFAULT_BACK_CAMERA LifecycleOwner = this 绑定 / 解绑结果 相机打开 预览流开始 画面实时刷新 相机释放 预览流停止 资源自动回收 无需手动 unbind 生命周期自动管理 findViewById getInstance 自动解绑

权限申请与绑定实现

CameraX 需要 CAMERA 权限。使用 registerForActivityResult 注册权限请求,在回调中判断授权结果,授权成功后再执行绑定。绑定前必须确保 PreviewView 已完成布局,否则 SurfaceProvider 可能为空。

class MainActivity : AppCompatActivity() {
    private lateinit var previewView: PreviewView
    private lateinit var cameraProvider: ProcessCameraProvider

    private val requestPermission =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
            if (granted) startCamera()
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        previewView = PreviewView(this)
        setContentView(previewView)

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
            == PackageManager.PERMISSION_GRANTED) {
            startCamera()
        } else {
            requestPermission.launch(Manifest.permission.CAMERA)
        }
    }

    private fun startCamera() {
        val future = ProcessCameraProvider.getInstance(this)
        future.addListener({
            cameraProvider = future.get()
            val preview = Preview.Builder().build().also {
                it.setSurfaceProvider(previewView.surfaceProvider)
            }
            cameraProvider.unbindAll()
            cameraProvider.bindToLifecycle(
                this,
                CameraSelector.DEFAULT_BACK_CAMERA,
                preview
            )
        }, ContextCompat.getMainExecutor(this))
    }
}
绑定前调用 unbindAll() 可避免重复绑定导致的 IllegalArgumentException,尤其在配置变更或多次进入页面时。

验证与常见问题

现象可能原因处理方式
预览黑屏权限未授予或绑定失败检查权限回调,确认 bindToLifecycle 无异常
画面拉伸变形PreviewView 缩放模式不匹配设置 previewView.scaleType = FILL_CENTER
切后台后相机未释放未使用 LifecycleOwner 绑定确保传入 this 作为 LifecycleOwner
重复进入崩溃重复绑定同一用例绑定前执行 unbindAll()
最小预览的验证标准:授权后画面在 1 秒内出现实时影像;按 Home 键后相机指示灯熄灭;返回应用后预览自动恢复。