如何在ViewModel中仅暴露含ScreenUiState和Paging3 Reviews的Flow?
能否在ViewModel外部仅暴露一个同时包含ScreenUiState和reviews(Paging 3 Flow)的Flow?
可以实现,但不能直接将reviews Flow作为属性放入ScreenUiState(正如你所说,这会导致Compose中的不稳定状态)。下面是两种可行的解决方案:
方案1:合并两个Flow为单一组合Flow
使用combine操作符将uiState和reviews两个Flow合并成一个新的Flow,对外暴露这个组合Flow即可。这样外部只需收集这一个Flow就能获取所有状态数据。
示例代码:
class ScreenViewModel : ViewModel() { private val reviews = Pager( config = PagingConfig(pageSize = 10), pagingSourceFactory = { ReviewsPagingSource() } ).flow private val _uiState = MutableStateFlow(ScreenUiState()) private val uiState: StateFlow<ScreenUiState> = _uiState // 对外暴露的组合状态Flow val combinedState = combine(uiState, reviews) { uiState, reviews -> Pair(uiState, reviews) }.stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = Pair(ScreenUiState(), PagingData.empty()) ) } // Compose中使用方式 @Composable fun Screen(viewModel: ScreenViewModel) { val (uiState, reviews) = viewModel.combinedState.collectAsState() Text(text = uiState.header ?: "") val lazyReviews = reviews.collectAsLazyPagingItems() LazyColumn { items(lazyReviews) { review -> review?.let { ReviewItem(it) } } } }
方案2:保持两个Flow独立暴露(官方推荐)
虽然需要收集两个Flow,但这是官方认可的方式——Paging 3的Flow<PagingData>有专门的collectAsLazyPagingItems()方法处理列表数据,能更好地利用分页库特性,彻底避免状态不稳定问题。
示例代码:
// ViewModel保持原有结构不变 class ScreenViewModel : ViewModel() { val reviews = Pager( config = PagingConfig(pageSize = 10), pagingSourceFactory = { ReviewsPagingSource() } ).flow private val _uiState = MutableStateFlow(ScreenUiState()) val uiState: StateFlow<ScreenUiState> = _uiState } // Compose中使用方式 @Composable fun Screen(viewModel: ScreenViewModel) { val uiState = viewModel.uiState.collectAsState() val lazyReviews = viewModel.reviews.collectAsLazyPagingItems() Text(text = uiState.value.header ?: "") LazyColumn { items(lazyReviews) { review -> review?.let { ReviewItem(it) } } // 处理加载、空数据等状态 lazyReviews.apply { when { loadState.refresh is LoadState.Loading -> { /* 显示加载中 */ } loadState.append is LoadState.Error -> { /* 显示加载错误 */ } } } } }
为什么不能将reviews Flow放入ScreenUiState?
当你把Flow<PagingData<Review>>作为ScreenUiState的属性时,Compose会将整个ScreenUiState判定为不稳定状态——Flow本身是带生命周期的对象,每次状态更新都会触发Compose全量重组,哪怕其他属性没有变化,既降低性能又可能引发不必要的UI异常。
内容的提问来源于stack exchange,提问作者Cosmin Mihu
相关产品推荐
相关产品推荐

