Android CameraX ничего не показывает - PullRequest
2 голосов
/ 09 мая 2019

Я реализовал новый образец, вот ссылка , которая описывает новый API CameraX из кодовых меток Google, но TextureView ничего не показывает и выдает следующее исключение:

OpenGLRenderer: [SurfaceTexture-0-7609-1] dequeueImage: SurfaceTexture не прикреплен к представлению

Другие образцы камер в качестве Camera2 и родного приложения камеры работают нормально Я использовал эмулятор с api level Q beta 3

class CameraXFragment : Fragment(), TextureView.SurfaceTextureListener {

    companion object {
        fun newInstance(): Fragment = CameraXFragment()
    }

    private val REQUEST_CODE_PERMISSIONS = 10
    private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.fragment_camera, container, false)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewFinder.surfaceTextureListener = this
    }

    private fun startCamera() {
        CameraX.unbindAll()

        val previewConfig = PreviewConfig.Builder().apply {
            setTargetAspectRatio(Rational(1, 1))
            setTargetResolution(Size(320, 320))
        }.build()

        val preview = Preview(previewConfig)
        preview.setOnPreviewOutputUpdateListener {
            viewFinder.surfaceTexture = it.surfaceTexture
            updateTransform()
        }

        val imageCaptureConfig = ImageCaptureConfig.Builder()
                .apply {
                    setTargetAspectRatio(Rational(1, 1))
                    setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
                }.build()

        val imageCapture = ImageCapture(imageCaptureConfig)
        captureButton.setOnClickListener {
            val file = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "${System.currentTimeMillis()}.jpg")
            imageCapture.takePicture(file,
                    object : ImageCapture.OnImageSavedListener {
                        override fun onError(error: ImageCapture.UseCaseError, message: String, t: Throwable?) {
                            t?.printStackTrace()
                        }

                        override fun onImageSaved(file: File) {
                            val msg = "Photo capture succeeded: ${file.absolutePath}"
                            Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
                        }
                    })
        }

        CameraX.bindToLifecycle(this, preview, imageCapture)
    }

    private fun updateTransform() {
        val matrix = Matrix()
        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
            else -> return
        }
        matrix.postRotate(-rotationDegrees.toFloat(), centerX, centerY)
        viewFinder.setTransform(matrix)
    }

    override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
    }

    override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
    }

    override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
        return true
    }

    override fun onSurfaceTextureAvailable(surface: SurfaceTexture?, width: Int, height: Int) {
        if (allPermissionsGranted()) {
            viewFinder.post { startCamera() }
        } else {
            requestPermissions(REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
        }
        viewFinder.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
            updateTransform()
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            if (allPermissionsGranted()) {
                viewFinder.post { startCamera() }
            } else {
                Toast.makeText(requireContext(), "Permissions are not granted", Toast.LENGTH_SHORT).show()
            }
        }
    }

    private fun allPermissionsGranted(): Boolean {
        for (permission in REQUIRED_PERMISSIONS) {
            if (ContextCompat.checkSelfPermission(requireContext(), permission) != PackageManager.PERMISSION_GRANTED) {
                return false
            }
        }
        return true
    }
}

Ответы [ 2 ]

4 голосов
/ 14 мая 2019

TextureView необходимо удалить и повторно добавить из родительского представления для прикрепления SurfaceTexture. Это связано с тем, что TextureView внутренне создает свою собственную SurfaceTexture, как только она присоединена к иерархии представления, и эта внутренняя SurfaceTexture корректно отсоединяется только после удаления родительского TextureView из иерархии представления. Вы должны изменить preview.setOnPreviewOutputUpdateListener на:

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

Похоже, что вы, возможно, скопировали код из кодовой метки, которая теперь была обновлена, чтобы включить повторное вложение представления. Официальный образец также реализует повторное вложение этого представления.

0 голосов
/ 10 мая 2019

Я столкнулся с той же проблемой, когда следовал codeLabs. Я заблокировал экран, затем снова включил его, и вдруг он заработал нормально, функция захвата тоже сработала. Я понятия не имею об этой ситуации, но вы можете попробовать этот способ в качестве обходного пути. Я использую Q beta 3 в Pixel 3.

PS: Вы можете просто вызвать события onStop и onStart для Activity (например, нажмите home и снова откройте приложение), предварительный просмотр будет работать. На мой взгляд, я думаю, что эта проблема связана с CameraX.bindToLifecycle.

...