相机 X 被另一个 startFocusAndMetering 取消

问题描述 投票:0回答:4

我正在使用cameraX 库实现自定义相机。我正在努力集中注意力,我做了以下事情

viewFinder.setOnTouchListener { v, event ->
            return@setOnTouchListener when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    true
                }
                MotionEvent.ACTION_UP -> {
                   // The below code is for focusing 

                    val factory = SurfaceOrientedMeteringPointFactory(
                        viewFinder.width.toFloat(),
                        viewFinder.height.toFloat()
                    )
                    val point = factory.createPoint(event.x, event.y)
                    try {
                        val action = FocusMeteringAction.Builder(point, FocusMeteringAction.FLAG_AF)
                            .apply {
                                disableAutoCancel() //focus only when the user tap the preview
                            }.build()

                        val future = cameraControl?.startFocusAndMetering(action)
                        future?.addListener(Runnable {
--->line 66                 val result = future?.get()
                            println("log result ---> $result")
                        }, cameraExecutor)

                    } catch (e: CameraInfoUnavailableException) {
                        println("log error ---> $e")
                    }
                    true
                }
                else -> false // Unhandled event.
            }
        }

现在,它是一些聚焦我所触及的点的东西,它不是太准确,但还可以。当聚焦 5 到 6 次后,应用程序崩溃并关闭。

FATAL EXCEPTION: pool-2-thread-1
...
...
java.lang.Error: java.util.concurrent.ExecutionException: androidx.camera.core.CameraControl$OperationCanceledException: Cancelled by another startFocusAndMetering()
...
...
...MainActivity$onCreate$2$1.run(MainActivity.kt:66)

我不明白为什么它会崩溃,而且它并不经常崩溃。有时会崩溃,有时不会。

编辑1:-

我知道当我多次点击焦点时就会发生这种情况。因此,在开始对焦之前,我需要清除之前的焦点(如果正在进行)。但是,如何清除之前的焦点我不明白。

编辑2:-

我尝试了这个

 cameraControl?.cancelFocusAndMetering()
,我只是将它放在 try 块的第一行。但仍然存在问题。

java android kotlin android-camera android-camerax
4个回答
3
投票

对这里的java代码表示歉意。但根据我的经验,future?.get() 需要包含在 try, catch 中

future.addListener(() -> {

    try
        {
            FocusMeteringResult result = (FocusMeteringResult) future.get();
            if(result.isFocusSuccessful())
            {
                // Focus has succeeded
            }
            else
            {
                // Focus has failed
            }
        }
        catch (ExecutionException e) // Thrown exceptions
        {
            e.printStackTrace();
        }
        catch (InterruptedException e) // Thrown exceptions
        {
            e.printStackTrace();
        }
}

1
投票

我刚刚删除了这个块

future?.addListener(Runnable {
          val result = future?.get()
          println("log result ---> $result")
       }, cameraExecutor)

并且运行良好。但我不知道这是对还是错。

有人知道吗?请回答。目前我将其标记为答案,因为它有效。


1
投票

正如您提到的,问题是由于 future?.addListener 造成的。为了解决这个问题,你可以在 viewFinder.setOnTouchListener 之外定义 future 变量:

private var future: ListenableFuture<FocusMeteringResult>? = null

在调用 startFocusAndMetering(action) 之前取消 future

future?.cancel(true)

所以你的最终代码看起来像这样:

private var future: ListenableFuture<FocusMeteringResult>? = null

viewFinder.setOnTouchListener { v, event ->
            return@setOnTouchListener when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    true
                }
                MotionEvent.ACTION_UP -> {
                   
                    future?.cancel(true)

                    // The below code is for focusing 

                    val factory = SurfaceOrientedMeteringPointFactory(
                        viewFinder.width.toFloat(),
                        viewFinder.height.toFloat()
                    )
                    val point = factory.createPoint(event.x, event.y)
                    try {
                        val action = FocusMeteringAction.Builder(point, FocusMeteringAction.FLAG_AF)
                            .apply {
                                disableAutoCancel() //focus only when the user tap the preview
                            }.build()

                        future = cameraControl?.startFocusAndMetering(action)
                        future?.addListener(Runnable {
--->line 66                 val result = future?.get()
                            println("log result ---> $result")
                        }, cameraExecutor)

                    } catch (e: CameraInfoUnavailableException) {
                        println("log error ---> $e")
                    }
                    true
                }
                else -> false // Unhandled event.
            }
        }

0
投票

我结合了上述解决方案来阻止 android compose 中的双击崩溃...

在可组合项中,

    var future: ListenableFuture<FocusMeteringResult>? = null

然后先取消future,之后调用focus设置future:

            previewView.setOnTouchListener { _, event ->
                future?.cancel(true)

                isFocusVisible = true
                if (event.action == MotionEvent.ACTION_UP) {
                    camera?.let {
                        focusPoint = Offset(event.x, event.y)
                        val factory: MeteringPointFactory = previewView.meteringPointFactory
                        val point: MeteringPoint = factory.createPoint(event.x, event.y)
                        val action = FocusMeteringAction.Builder(point).build()
                        future = camera?.cameraControl?.startFocusAndMetering(action)
                        isFocusVisible = false
                    }
                }
                true
            }

对我有用,不需要任何 try-catch 逻辑。

© www.soinside.com 2019 - 2024. All rights reserved.