Kotlin中多API依赖调用的列表数据对齐问题求解
问题根源分析
你的代码出现图片与品种数据不对齐的核心原因如下:
- ViewModel中使用**单一状态
breedImageByID**存储图片数据,遍历品种列表时连续发起图片请求会不断覆盖这个状态,最终所有列表项都会显示最后一次请求返回的图片。 BreedListItem组件接收了catImage参数却未使用,反而依赖全局共享状态,进一步加剧了数据不匹配问题。- 异步请求的执行顺序不可控,无法保证图片请求结果与品种的对应关系。
解决方案
核心思路是用**键值对(Map)**存储每个品种对应的图片数据,将reference_image_id作为Key,确保每个品种的图片独立存储,不会被覆盖。
1. 修改ViewModel数据结构与逻辑
将原来的单一图片状态替换为Map,用于关联每个图片ID对应的请求结果:
class BreedSharedViewModel(private val repository: BreedRepository) : ViewModel() { val breeds: MutableState<NetworkResult<GetBreeds>> = mutableStateOf(NetworkResult.Loading()) // 用Map存储每个图片ID对应的请求结果,Key为reference_image_id val breedImages: MutableState<Map<String, NetworkResult<CatImage>>> = mutableStateOf(emptyMap()) private fun getBreeds() = viewModelScope.launch { repository.getBreeds().collect { values -> breeds.value = values values.data?.forEach { breed -> breed.reference_image_id?.let { imageId -> // 避免重复请求已加载的图片 if (!breedImages.value.containsKey(imageId)) { breedImageByID(imageId) } } } } } fun breedImageByID(referenceImageId: String) = viewModelScope.launch { repository.getCatImageByID(referenceImageId).collect { result -> // 更新Map,保留原有数据,仅更新当前图片ID的结果 breedImages.value = breedImages.value + (referenceImageId to result) } } }
2. 调整列表项组件逻辑
移除无用的catImage参数,直接根据当前品种的reference_image_id从Map中获取对应图片:
@Composable fun BreedListItem( breed: BreedItem, viewModel: BreedSharedViewModel, navController: NavController ) { // 根据当前品种的图片ID获取对应的请求结果 val imageResult = breed.reference_image_id?.let { viewModel.breedImages.value[it] } ?: NetworkResult.Loading() // 根据请求状态处理图片URL val breedImageURL = when (imageResult) { is NetworkResult.Success -> imageResult.data?.url ?: "" else -> "" // 加载中/失败时可替换为占位图URL } Row( modifier = Modifier .fillMaxSize() .padding(6.dp) .clip(RoundedCornerShape(18.dp)) .background(Color.Gray) .clickable { viewModel.addBreedItem(breed) navController.navigate(DetailsNavScreen.BreedsDetail.route) }, verticalAlignment = Alignment.CenterVertically ) { Box( modifier = Modifier .width(120.dp) .height(80.dp) .clip(RoundedCornerShape(12.dp)) ) { // 可添加加载状态/错误状态的UI if (imageResult is NetworkResult.Loading) { CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) } else { SubcomposeAsyncImage( model = breedImageURL, contentDescription = breed.name, contentScale = ContentScale.FillBounds ) } } Text( text = breed.name, modifier = Modifier.padding(start = 15.dp), fontWeight = FontWeight.ExtraBold, fontSize = 17.sp ) } Spacer(modifier = Modifier.height(10.dp)) }
额外优化建议
- 可以给加载失败的情况添加默认占位图,提升用户体验。
- 若API支持,可考虑在
getBreeds接口中直接返回图片URL,减少一次网络请求。
内容的提问来源于stack exchange,提问作者Sky
相关产品推荐
相关产品推荐

