You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin开发相机应用运行时切换不同ML模型的实现问题咨询

实现方案

1. 抽取公共复用变量,消除冗余代码

将你重复编写的预览、相机选择器、相机管理实例抽为Activity全局成员变量,仅在第一次初始化相机时创建,后续切换模型全程复用:

// 新增全局成员变量
private lateinit var cameraProvider: ProcessCameraProvider
private lateinit var preview: Preview
private lateinit var cameraSelector: CameraSelector
// 新增模式管理枚举
private enum class CameraMode {
    NONE, OBJECT_DETECTION, SCENE_RECOGNITION, CURRENCY_DETECTION, OBSTACLE_DETECTION, HUMAN_HUMAN_INTERACTION
}
private var currentMode: CameraMode = CameraMode.NONE

修改权限获批后的初始化逻辑,仅在这里创建一次公共实例:

override fun onPermissionsGranted(requestCode: Int, perms: List<String>) {
    cameraProviderFuture = ProcessCameraProvider.getInstance(this)
    cameraProviderFuture.addListener({
        // 初始化公共复用变量
        cameraProvider = cameraProviderFuture.get()
        preview = Preview.Builder().build()
        cameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
        preview.setSurfaceProvider(binding.previewView.surfaceProvider)
        // 默认启动无模型模式
        switchCameraMode(CameraMode.NONE)
    }, ContextCompat.getMainExecutor(this))
    // 其余原有逻辑保持不变
}

2. 编写统一的模式切换方法

所有模型切换都通过这个统一方法处理,自动解绑旧用例、绑定新用例:

private fun switchCameraMode(targetMode: CameraMode) {
    // 先解绑所有已绑定的用例
    cameraProvider.unbindAll()
    currentMode = targetMode

    when(targetMode) {
        CameraMode.NONE -> {
            // 无模型模式仅绑定预览
            cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, preview)
        }
        CameraMode.OBJECT_DETECTION -> {
            // 提前初始化模型(可加判空避免重复加载)
            if (!::objectDetector.isInitialized) {
                readyObjectDetectionModel()
            }
            // 创建目标检测对应的ImageAnalysis用例
            val imageAnalysis = ImageAnalysis.Builder().setTargetResolution(Size(1280, 720))
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).build()
            imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this)) { imageProxy ->
                val rotationDegrees = imageProxy.imageInfo.rotationDegrees
                val image = imageProxy.image
                if (image != null) {
                    val processImage = InputImage.fromMediaImage(image, rotationDegrees)
                    objectDetector.process(processImage)
                        .addOnSuccessListener { imageProxy.close() }
                        .addOnFailureListener { imageProxy.close() }
                }
            }
            // 绑定预览+目标检测分析用例
            cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, imageAnalysis, preview)
        }
        // 其余4类模型的绑定逻辑按上面的格式补充即可
        else -> {}
    }
}

3. 按钮触发逻辑

你已经做好的切换按钮,点击时直接调用切换方法即可,比如目标检测按钮的点击逻辑:

binding.objectDetectionBtn.setOnClickListener {
    switchCameraMode(CameraMode.OBJECT_DETECTION)
}
// 无模型模式按钮点击逻辑
binding.noModelBtn.setOnClickListener {
    switchCameraMode(CameraMode.NONE)
}

疑问解答

  • 能否仅修改已绑定的用例?可以,CameraX的bindToLifecycle方法会自动替换同生命周期下已绑定的同类型用例,不过主动调用unbindAll再绑定新用例更稳妥,可避免旧用例后台占用资源。
  • 要不要做CameraFragment?如果相机逻辑仅在当前页面使用,完全不需要,上述方案足够简洁。如果后续多个页面需要复用相机能力,再抽成独立Fragment即可。

内容的提问来源于stack exchange,提问作者M Tayyab Asghar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 19:15:04