我已经实现了一个新示例,这里是a link https://codelabs.developers.google.com/codelabs/camerax-getting-started/#0它描述了来自 Google Codelabs 的新 CameraX api,但 TextureView 不显示任何内容并抛出下一个异常:
OpenGLRenderer:[SurfaceTexture-0-7609-1] dequeueImage:SurfaceTexture 未附加到视图
其他相机示例(例如 Camera2 和本机相机应用程序)运行良好
我使用了 API 级别 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<String>, 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
}
}