You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 21:22:46