Android Kotlin(Jetpack Compose)中如何日志输出PreviewView.bitmap?
解决PreviewView获取Bitmap返回Null的问题
要解决previewView.bitmap返回null的问题,核心是监听PreviewView的流状态,等待其进入STREAMING状态后再获取Bitmap。以下是针对你的Compose代码的修改方案:
实现步骤
- 给PreviewView添加流状态变化监听器,监听
StreamState的切换 - 当状态变为
PreviewView.StreamState.STREAMING时,安全获取Bitmap - 若需要实时获取Bitmap,可配合协程定时执行获取逻辑
修改后的完整代码
package com.example.livestreamdemo.screens import android.Manifest import android.content.pm.PackageManager import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.camera.core.CameraSelector import androidx.camera.core.Preview import androidx.camera.lifecycle.ProcessCameraProvider import androidx.camera.view.PreviewView import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.viewinterop.AndroidView import androidx.core.content.ContextCompat import com.example.livestreamdemo.util.Common.REQUIRED_PERMISSIONS import kotlinx.coroutines.delay import kotlinx.coroutines.launch @Composable fun CameraPreviewScreen() { val lifecycleOwner = LocalLifecycleOwner.current val context = LocalContext.current val cameraProviderNext = remember { ProcessCameraProvider.getInstance(context) } val coroutineScope = rememberCoroutineScope() var hasCamPermission by remember { mutableStateOf( REQUIRED_PERMISSIONS.all { ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED }) } val launcher = rememberLauncherForActivityResult( contract = ActivityResultContracts.RequestMultiplePermissions(), onResult = { granted -> hasCamPermission = granted.values.all { it } } ) LaunchedEffect(key1 = true) { launcher.launch( arrayOf( Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE ) ) } if(hasCamPermission) { AndroidView( factory = { ctx -> val previewView = PreviewView(ctx) val exec = ContextCompat.getMainExecutor(ctx) cameraProviderNext.addListener({ val cameraProvider = cameraProviderNext.get() val preview = Preview.Builder().build() .also { it.setSurfaceProvider(previewView.surfaceProvider) } val cameraSelector = CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK) .build() cameraProvider.unbindAll() cameraProvider.bindToLifecycle( lifecycleOwner, cameraSelector, preview ) }, exec) // 监听预览流状态变化 val streamStateListener = PreviewView.OnPreviewStreamStateChangedListener { state -> if (state == PreviewView.StreamState.STREAMING) { Log.d("CameraPreview", "预览已启动,开始获取Bitmap") // 单次获取Bitmap val bitmap = previewView.bitmap bitmap?.let { Log.d("CameraPreview", "获取到Bitmap: 宽=${it.width}, 高=${it.height}") } ?: Log.w("CameraPreview", "Bitmap仍为Null") // 若需要实时获取,启动协程定时执行 coroutineScope.launch { while (true) { delay(1000) // 每秒获取一次,可调整间隔 val realtimeBitmap = previewView.bitmap realtimeBitmap?.let { Log.d("CameraPreview", "实时Bitmap: 宽=${it.width}, 高=${it.height}") } } } // 如果只需要监听一次,可移除监听器 // previewView.removeOnPreviewStreamStateChangedListener(this) } } previewView.addOnPreviewStreamStateChangedListener(streamStateListener) // View销毁时移除监听器,避免内存泄漏 previewView.addOnAttachStateChangeListener(object : android.view.View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: android.view.View) {} override fun onViewDetachedFromWindow(v: android.view.View) { previewView.removeOnPreviewStreamStateChangedListener(streamStateListener) } }) previewView }, modifier = Modifier.fillMaxSize(), ) } }
关键说明
- 流状态判断:只有当
StreamState为STREAMING时,预览才真正处于活跃状态,此时调用previewView.bitmap才能大概率获取到有效数据。 - 内存泄漏防护:通过
OnAttachStateChangeListener在View从窗口分离时移除监听器,避免潜在的内存泄漏问题。 - 权限判断优化:将原代码中
granted.size == 2改为granted.values.all { it },确保所有请求的权限都被用户授予。 - 实时获取逻辑:使用协程和
delay实现定时获取,可根据业务需求调整获取间隔。
内容的提问来源于stack exchange,提问作者Noah Camara
相关产品推荐
相关产品推荐

