Jetpack Compose中MVVM模式下SurfaceView与ViewModel交互问题
优化方案:用DisposableEffect实现解耦的MVVM架构
你的核心问题在于ViewModel持有视图层的SurfaceView,这既违反了MVVM的职责分离原则(ViewModel不应依赖视图组件),还可能导致内存泄漏(ViewModel生命周期远长于视图)。下面是用DisposableEffect优化的实现,完全符合MVVM规范:
1. 重构ViewModel:剥离视图依赖
ViewModel只负责管理流的可用性状态,以及提供启动/停止流的方法(需要视图层传入SurfaceView,而非持有它):
class CameraVM : ViewModel() { // 暴露流是否可用的状态,供视图层监听 private val _isStreamSourceAvailable = MutableStateFlow(false) val isStreamSourceAvailable = _isStreamSourceAvailable.asStateFlow() init { listenForStreamSourceAvailability() } private fun listenForStreamSourceAvailability() { // 替换为实际的SDK源可用性监听逻辑 viewModelScope.launch { // 模拟源可用的回调 _isStreamSourceAvailable.value = true } } // 启动流:由视图层传入准备好的SurfaceView fun startStreaming(surfaceView: SurfaceView) { camera.setupStreaming(surfaceView) camera.startStreaming() } // 可选:根据业务需求实现停止流的逻辑 fun stopStreaming() { camera.stopStreaming() } }
2. 重构Compose视图:用DisposableEffect处理生命周期与状态联动
在CameraView中,用DisposableEffect监听视图组合状态和流源的可用性,满足你要求的两种启动场景,同时避免ViewModel与视图耦合:
@Composable fun CameraView(viewModel: CameraVM = viewModel()) { val context = LocalContext.current // 监听流源是否可用的状态 val isSourceAvailable by viewModel.isStreamSourceAvailable.collectAsState() // 用remember缓存SurfaceView,避免重复创建 val surfaceView = remember { SurfaceView(context) } // 渲染SurfaceView AndroidView(factory = { surfaceView }) // 用DisposableEffect处理视图生命周期与状态变化 DisposableEffect(surfaceView, isSourceAvailable) { // 场景1:视图首次组合且源可用;场景2:源变为可用且视图可见 if (isSourceAvailable) { viewModel.startStreaming(surfaceView) } // 当Compose节点被销毁时执行清理(比如释放Surface资源、停止流) onDispose { viewModel.stopStreaming() } } }
方案优势
- 严格遵循MVVM:ViewModel不再依赖任何视图层组件,只专注业务状态和逻辑,视图层负责视图渲染和生命周期回调。
- 满足启动场景:
DisposableEffect会在surfaceView或isSourceAvailable发生变化时触发,完美覆盖你要求的两种启动时机。 - 避免内存泄漏:
onDispose回调会在视图销毁时执行清理,确保Surface资源和流的正确释放。
内容的提问来源于stack exchange,提问作者Big Bro
相关产品推荐
相关产品推荐

