admin管理员组文章数量:1391969
I am trying to implement camera functionallity to my android app. I use jetpack compose and I saw they have updated cameraX library to support it. I followed these medium tutorials:
Part 1:
Part 2:
And at first it worked. Then I tried to add some overlay to the camera preview, like an info text to explain to the user what to do. And if I do:
uiState.surfaceRequest?.let { request ->
CameraXViewfinder(
surfaceRequest = request,
modifier = modifier
.fillMaxSize()
)
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.padding(
end = 48.dp,
bottom = dimensionResource(R.dimen.padding_medium)
)
.background(Color.LightGray.copy(alpha = 0.5f), MaterialTheme.shapes.small)
.width(275.dp)
) {
Text(
text = "Scan a qr code or point at a place to see more details about it!",
modifier = Modifier
.padding(dimensionResource(R.dimen.padding_small))
)
}
It still works fine. But I decided that I want to add a button that when clicked will show the row and after 5 seconds it will disappear, like this:
@Composable
fun CameraScreen(
modifier: Modifier = Modifier,
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
cameraViewModel: CameraViewModel = CameraViewModel(),
) {
val uiState = cameraViewModel.uiState.collectAsStateWithLifecycle().value
val context = LocalContext.current
LaunchedEffect(lifecycleOwner) {
cameraViewModel.bindToCamera(context.applicationContext, lifecycleOwner)
}
uiState.surfaceRequest?.let { request ->
CameraXViewfinder(
surfaceRequest = request,
modifier = modifier
.fillMaxSize()
)
Box(
contentAlignment = Alignment.BottomEnd,
modifier = Modifier
.fillMaxSize()
) {
AnimatedVisibility(
visible = uiState.isInfoScreenOpen
) {
LaunchedEffect(Unit) {
delay(5000)
cameraViewModel.toggleInfoScreen()
}
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.padding(
end = 48.dp,
bottom = dimensionResource(R.dimen.padding_medium)
)
.background(Color.LightGray.copy(alpha = 0.5f), MaterialTheme.shapes.small)
.width(275.dp)
) {
Text(
text = "Scan a qr code or point at a place to see more details about it!",
modifier = Modifier
.padding(dimensionResource(R.dimen.padding_small))
)
}
}
IconButton(
onClick = cameraViewModel::toggleInfoScreen
) {
Icon(
painter = painterResource(R.drawable.round_info_outline_24),
contentDescription = "Info button",
tint = Color.White
)
}
}
}
}
It doesn't work anymore and when I press the button or the delay passes the screen disappears and I only see the background and I get the "SurfaceView BufferQueue has been abandoned" error in logcat.
My uiState data class:
data class CameraUiState (
// Used to set up a link between the Camera and your UI.
val surfaceRequest: SurfaceRequest? = null,
val qrContent: Uri? = null,
val isInfoScreenOpen: Boolean = true
)
My viewModel code:
private val _uiState = MutableStateFlow(CameraUiState())
val uiState: StateFlow<CameraUiState> = _uiState.asStateFlow()
private val executor = Executors.newSingleThreadExecutor()
private val cameraPreview = Preview.Builder().build().apply {
setSurfaceProvider { newSurfaceRequest ->
_uiState.update {
it.copy(
surfaceRequest = newSurfaceRequest
)
}
}
}
fun toggleInfoScreen() {
_uiState.update {
it.copy(
isInfoScreenOpen = !it.isInfoScreenOpen
)
}
}
suspend fun bindToCamera(appContext: Context, lifecycleOwner: LifecycleOwner) {
val processCameraProvider = ProcessCameraProvider.awaitInstance(appContext)
processCameraProvider.bindToLifecycle(
lifecycleOwner, DEFAULT_BACK_CAMERA, cameraPreview, imageAnalysis
)
// Cancellation signals we're done with the camera
try { awaitCancellation() } finally { processCameraProvider.unbindAll() }
}
I tried to move surfaceRequest out of the uiState, so that it was collected separetly, so it doesn't depend on the other fields of the uiState. I tried to move the call for the creation of the viewModel in the NavHost and not directly into the composable, but this gives me the same error without even starting the camera. I tried moving out all the code except the CameraXViewfinder out of the let block, so that it doesn't depend on the existing of surfaceRequest and it renders before the camera, yes, but after I click the button the whole thing disappears, i.e. both the camera view and the row and button composables. I first tried implementing a scaffold as a container and the button was a floating action button, because I thought it would be easier. I tried wrapping the code shown above into another box, to simplify the code, and then I removed the whole wrapping container. I tried to copy as much as possible the code from the second part of the medium tutorial and I see no logical differences between that and my solution. I tried asking ai with no result. I don't know what else to do and I do not understand how to fix this, because I do not understand why exatcly it is happening.
I appreaciate all the help I can get.
I am trying to implement camera functionallity to my android app. I use jetpack compose and I saw they have updated cameraX library to support it. I followed these medium tutorials:
Part 1: https://medium/androiddevelopers/getting-started-with-camerax-in-jetpack-compose-781c722ca0c4
Part 2: https://medium/androiddevelopers/tap-to-focus-mastering-camerax-transformations-in-jetpack-compose-440853280a6e
And at first it worked. Then I tried to add some overlay to the camera preview, like an info text to explain to the user what to do. And if I do:
uiState.surfaceRequest?.let { request ->
CameraXViewfinder(
surfaceRequest = request,
modifier = modifier
.fillMaxSize()
)
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.padding(
end = 48.dp,
bottom = dimensionResource(R.dimen.padding_medium)
)
.background(Color.LightGray.copy(alpha = 0.5f), MaterialTheme.shapes.small)
.width(275.dp)
) {
Text(
text = "Scan a qr code or point at a place to see more details about it!",
modifier = Modifier
.padding(dimensionResource(R.dimen.padding_small))
)
}
It still works fine. But I decided that I want to add a button that when clicked will show the row and after 5 seconds it will disappear, like this:
@Composable
fun CameraScreen(
modifier: Modifier = Modifier,
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
cameraViewModel: CameraViewModel = CameraViewModel(),
) {
val uiState = cameraViewModel.uiState.collectAsStateWithLifecycle().value
val context = LocalContext.current
LaunchedEffect(lifecycleOwner) {
cameraViewModel.bindToCamera(context.applicationContext, lifecycleOwner)
}
uiState.surfaceRequest?.let { request ->
CameraXViewfinder(
surfaceRequest = request,
modifier = modifier
.fillMaxSize()
)
Box(
contentAlignment = Alignment.BottomEnd,
modifier = Modifier
.fillMaxSize()
) {
AnimatedVisibility(
visible = uiState.isInfoScreenOpen
) {
LaunchedEffect(Unit) {
delay(5000)
cameraViewModel.toggleInfoScreen()
}
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.padding(
end = 48.dp,
bottom = dimensionResource(R.dimen.padding_medium)
)
.background(Color.LightGray.copy(alpha = 0.5f), MaterialTheme.shapes.small)
.width(275.dp)
) {
Text(
text = "Scan a qr code or point at a place to see more details about it!",
modifier = Modifier
.padding(dimensionResource(R.dimen.padding_small))
)
}
}
IconButton(
onClick = cameraViewModel::toggleInfoScreen
) {
Icon(
painter = painterResource(R.drawable.round_info_outline_24),
contentDescription = "Info button",
tint = Color.White
)
}
}
}
}
It doesn't work anymore and when I press the button or the delay passes the screen disappears and I only see the background and I get the "SurfaceView BufferQueue has been abandoned" error in logcat.
My uiState data class:
data class CameraUiState (
// Used to set up a link between the Camera and your UI.
val surfaceRequest: SurfaceRequest? = null,
val qrContent: Uri? = null,
val isInfoScreenOpen: Boolean = true
)
My viewModel code:
private val _uiState = MutableStateFlow(CameraUiState())
val uiState: StateFlow<CameraUiState> = _uiState.asStateFlow()
private val executor = Executors.newSingleThreadExecutor()
private val cameraPreview = Preview.Builder().build().apply {
setSurfaceProvider { newSurfaceRequest ->
_uiState.update {
it.copy(
surfaceRequest = newSurfaceRequest
)
}
}
}
fun toggleInfoScreen() {
_uiState.update {
it.copy(
isInfoScreenOpen = !it.isInfoScreenOpen
)
}
}
suspend fun bindToCamera(appContext: Context, lifecycleOwner: LifecycleOwner) {
val processCameraProvider = ProcessCameraProvider.awaitInstance(appContext)
processCameraProvider.bindToLifecycle(
lifecycleOwner, DEFAULT_BACK_CAMERA, cameraPreview, imageAnalysis
)
// Cancellation signals we're done with the camera
try { awaitCancellation() } finally { processCameraProvider.unbindAll() }
}
I tried to move surfaceRequest out of the uiState, so that it was collected separetly, so it doesn't depend on the other fields of the uiState. I tried to move the call for the creation of the viewModel in the NavHost and not directly into the composable, but this gives me the same error without even starting the camera. I tried moving out all the code except the CameraXViewfinder out of the let block, so that it doesn't depend on the existing of surfaceRequest and it renders before the camera, yes, but after I click the button the whole thing disappears, i.e. both the camera view and the row and button composables. I first tried implementing a scaffold as a container and the button was a floating action button, because I thought it would be easier. I tried wrapping the code shown above into another box, to simplify the code, and then I removed the whole wrapping container. I tried to copy as much as possible the code from the second part of the medium tutorial and I see no logical differences between that and my solution. I tried asking ai with no result. I don't know what else to do and I do not understand how to fix this, because I do not understand why exatcly it is happening.
I appreaciate all the help I can get.
Share Improve this question asked Mar 13 at 23:15 AngelAngel 11 bronze badge1 Answer
Reset to default 0The problem with this code was that in the screen composable I create the viewModel with the class constructor, like so:
@Composable
fun CameraScreen(
modifier: Modifier = Modifier,
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
cameraViewModel: CameraViewModel = CameraViewModel(),
)
Which doesn't make it part of the composition, nor does it save its state. To solve this I just changed the assignment of the default value as follows:
@Composable
fun CameraScreen(
modifier: Modifier = Modifier,
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
cameraViewModel: CameraViewModel = viewModel()
)
And now everything works correctly!
本文标签:
版权声明:本文标题:android - "SurfaceView BufferQueue has been abandoned" error when using CameraXViewfinder composable with Anim 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744680267a2619362.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论