CameraX - 取消绑定预览用例时崩溃

CameraX - crash when unbinding Preview UseCase

我需要在用户开始拍照时冻结(停止)预览。我四处搜索,发现 SO post 提到了取消绑定预览用例。我试过了,起初它在 Android 9+ 上正常工作,但在较低的 Android 上,我在 Logcat 中收到以下错误并且没有拍摄照片。

ImageCapture: takePictureInternal onFailure

androidx.camera.core.ImageCaptureException: The completer object was garbage collected - this future would otherwise never complete. The tag was: FutureChain[androidx.camera.core.impl.utils.futures.ChainingListenableFuture@3ee79178]
        at androidx.camera.core.ImageCapture$ImageCaptureRequest.lambda$notifyCallbackError$ImageCapture$ImageCaptureRequest(ImageCapture.java:1911)
        at androidx.camera.core.-$$Lambda$ImageCapture$ImageCaptureRequestG7WSvt8TANxhZtOyewefm68pg4.run(lambda)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5221)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
     Caused by: androidx.concurrent.futures.CallbackToFutureAdapter$FutureGarbageCollectedException: The completer object was garbage collected - this future would otherwise never complete. The tag was: FutureChain[androidx.camera.core.impl.utils.futures.ChainingListenableFuture@3ee79178]

还有很多日志开始出现

gralloc_ranchu: gralloc_lock usage mismatch usage=0x30 cb->usage=0x3

我怀疑我检索 ProcessCameraProvider 实例的方式是错误的 - 我只是在从 getInstance 方法返回的 Future 中获取后存储它并在以后使用它。但是当我再次尝试获得未来时,它并没有帮助。我没有找到解决此问题的方法,我正在考虑用其他相机库替换 CameraX,因为我在这上面花了太多时间,但也许有人有一些答案。

我创建了一个 demo project 来测试这个奇怪的行为,这样你就可以查看完整的代码。

事实上,我 post 在另一个 post 中使用的解决方案不适用于旧手机。我在 android 7 上对其进行了测试,但出现以下错误:

E/AndroidRuntime: FATAL EXCEPTION: CameraX-camerax_io_0 Process: com.hermosodev.camerax, PID: 23735 java.lang.IllegalStateException: Image is already closed at android.media.Image.throwISEIfImageIsInvalid(Image.java:68) at android.media.ImageReader$SurfaceImage.getFormat(ImageReader.java:679) at androidx.camera.core.AndroidImageProxy.getFormat(AndroidImageProxy.java:78) at androidx.camera.core.ForwardingImageProxy.getFormat(ForwardingImageProxy.java:75) at androidx.camera.core.ForwardingImageProxy.getFormat(ForwardingImageProxy.java:75) at androidx.camera.core.ForwardingImageProxy.getFormat(ForwardingImageProxy.java:75) at androidx.camera.core.ImageUtil.imageToJpegByteArray(ImageUtil.java:51) at androidx.camera.core.ImageSaver.run(ImageSaver.java:95) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) at java.lang.Thread.run(Thread.java:761)

使用我的 android 7 时,当我拍摄图片时,预览会在发布之前自动冻结一小段时间(这可以解释我的错误)。

OnImageSavedCallback 中冻结预览怎么样?

runOnUiThread {
   cameraProvider.unbind(previewUseCase)
}

我已将此作为错误发布到 Google Issue tracker,此错误是预期行为。要冻结预览,您不应该取消绑定预览用例。将来可能会有 API,但目前推荐的方法是存储来自 ImageAnalysis 的最新帧并将其放入与预览重叠的 ImageView。