8

我已经实现了一个新示例,这里是一个链接,它描述了来自 Google 代码实验室的新 CameraX api,但 TextureView 没有显示任何内容并引发下一个异常:

OpenGLRenderer:[SurfaceTexture-0-7609-1] dequeueImage:SurfaceTexture 未附加到视图

另一个相机样本作为 Camera2 和本机相机应用程序工作正常我使用了带有 api 级别 Q beta 3 的模拟器

类CameraXFragment:片段(),TextureView.SurfaceTextureListener {

    伴随对象{
        有趣的 newInstance(): Fragment = CameraXFragment()
    }

    私人 val REQUEST_CODE_PERMISSIONS = 10
    私有 val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)

    覆盖 fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.fragment_camera,容器,假)

    覆盖乐趣 onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewFinder.surfaceTextureListener = 这个
    }

    私人乐趣 startCamera() {
        CameraX.unbindAll()

        val previewConfig = PreviewConfig.Builder().apply {
            setTargetAspectRatio(Rational(1, 1))
            setTargetResolution(大小(320, 320))
        }。建造()

        val 预览 = 预览(previewConfig)
        preview.setOnPreviewOutputUpdateListener {
            viewFinder.surfaceTexture = it.surfaceTexture
            更新转换()
        }

        val imageCaptureConfig = ImageCaptureConfig.Builder()
                。申请 {
                    setTargetAspectRatio(Rational(1, 1))
                    setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
                }。建造()

        val imageCapture = ImageCapture(imageCaptureConfig)
        captureButton.setOnClickListener {
            val 文件 = 文件(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),“${System.currentTimeMillis()}.jpg”)
            imageCapture.takePicture(文件,
                    对象:ImageCapture.OnImageSavedListener {
                        覆盖 fun onError(error: ImageCapture.UseCaseError, message: String, t: Throwable?) {
                            t?.printStackTrace()
                        }

                        覆盖乐趣 onImageSaved(file: File) {
                            val msg = "照片拍摄成功:${file.absolutePath}"
                            Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
                        }
                    })
        }

        CameraX.bindToLifecycle(this, preview, imageCapture)
    }

    私人乐趣 updateTransform() {
        val 矩阵 = 矩阵()
        val centerX = viewFinder.width / 2f
        val centerY = viewFinder.height / 2f
        val rotationDegrees = when (viewFinder.display.rotation) {
            Surface.ROTATION_0 -> 0
            Surface.ROTATION_90 -> 90
            Surface.ROTATION_180 -> 180
            Surface.ROTATION_270 -> 270
            否则->返回
        }
        matrix.postRotate(-rotationDegrees.toFloat(), centerX, centerY)
        viewFinder.setTransform(矩阵)
    }

    覆盖乐趣 onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
    }

    覆盖乐趣 onSurfaceTextureUpdated(surface: SurfaceTexture) {
    }

    覆盖乐趣 onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
        返回真
    }

    覆盖乐趣 onSurfaceTextureAvailable(surface: SurfaceTexture?, width: Int, height: Int) {
        if (allPermissionsGranted()) {
            viewFinder.post { startCamera() }
        } 别的 {
            请求权限(REQUIRED_PERMISSIONS,REQUEST_CODE_PERMISSIONS)
        }
        viewFinder.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
            更新转换()
        }
    }

    覆盖乐趣 onRequestPermissionsResult(requestCode: Int, 权限: Array, grantResults: IntArray) {
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            if (allPermissionsGranted()) {
                viewFinder.post { startCamera() }
            } 别的 {
                Toast.makeText(requireContext(), "权限未授予", Toast.LENGTH_SHORT).show()
            }
        }
    }

    私人乐趣 allPermissionsGranted(): Boolean {
        for(REQUIRED_PERMISSIONS 中的权限){
            if (ContextCompat.checkSelfPermission(requireContext(), permission) != PackageManager.PERMISSION_GRANTED) {
                返回假
            }
        }
        返回真
    }
}
4

5 回答 5

19

需要从父视图中删除并重新添加 TextureView 才能附加 SurfaceTexture。这是因为 TextureView 一旦附加到视图层次结构,就会在内部创建自己的 SurfaceTexture,并且只有在从视图层次结构中删除父 TextureView 时,内部 SurfaceTexture 才会正确分离。您应该更改preview.setOnPreviewOutputUpdateListener为:

preview.setOnPreviewOutputUpdateListener {
    val parent = viewFinder.parent as ViewGroup
    parent.removeView(viewFinder)
    viewFinder.surfaceTexture = it.surfaceTexture
    parent.addView(viewFinder, 0)
    updateTransform()
}

看起来您可能已经从 codelab 复制了代码,该代码现已更新为包含视图重新附件。官方示例也实现了这个视图重附加。

于 2019-05-14T00:11:11.923 回答
4

Oscar Wahltinez在 Java 中的Kotlin代码:

ViewGroup parent = (ViewGroup) textureView.getParent();
parent.removeView(textureView);
parent.addView(textureView, 0);
SurfaceTexture surfaceTexture = previewOutput.getSurfaceTexture();
textureView.setSurfaceTexture(surfaceTexture);
于 2019-10-26T06:30:21.320 回答
2

我在关注 codeLabs 时遇到了同样的问题。我锁定屏幕然后再次打开它,突然它可以正常工作了,捕获功能也可以正常工作。我对这种情况一无所知,但您可以尝试这种方式作为解决方法。我在 Pixel 3 中使用 Q beta 3。

PS:您可以只为Activity触发onStop和onStart事件(例如:按home并再次打开应用程序),实时预览将起作用。在我看来,我认为这个问题与CameraX.bindToLifecycle.

于 2019-05-10T10:28:53.803 回答
1

除了这个答案。hardwareAccelerated="false"我通过从 AndroidManifest.xml 文件中删除应用程序级别行解决了我的问题。

于 2021-09-03T16:59:41.447 回答
0

这段代码对我有用

  val parent = viewFinder.parent as ViewGroup
  parent.removeView(viewFinder)
  parent.addView(viewFinder, 0)
  val surfaceTexture: SurfaceTexture = it.surfaceTexture
  viewFinder.setSurfaceTexture(surfaceTexture)
于 2020-06-27T14:47:56.803 回答