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

Retrofit2获取API数据存入MutableList后列表为空问题求助

问题分析与解决方案

核心问题定位

  • ViewModel实例不统一:GetData里创建的TournamentStateViewModel和TabSyncCompose里的不是同一个实例,API数据添加到了另一个ViewModel的集合里,UI观察的集合自然为空。
  • 数据集合无效:data = ArrayList(3)只是初始化了容量,没有添加任何元素,forEach循环根本不会执行,导致Category里的内容为空。
  • 预览函数逻辑错误:预览函数不会触发真实API请求流程,直接判断列表为空,所以永远弹出提示。

具体修复步骤

1. 统一ViewModel实例传递

不要在GetData中单独获取ViewModel,而是从上层函数传入,确保整个流程共用同一个实例:

修改GetData函数:

@Composable
fun GetData(
    team: TeamStatsResponse, 
    rankList: List<StandingsItemItem?>,
    viewModel: TournamentStateViewModel // 从外部传入统一的ViewModel
) {
    // 初始化有效索引集合,比如取前3名数据
    val top3Indices = listOf(0, 1, 2)
    
    viewModel.addTournamentItem(
        Category(
            title = "Standings",
            icon = Icons.Default.TableRows,
            onClick = {},
            // 用lambda包裹子Composable,确保内容能被正确渲染
            content = {
                top3Indices.forEach { index ->
                    rankList[index]?.let { item ->
                        TopTeamsPoints(
                            rank = item.rank ?: 0,
                            logo = item.team?.logo ?: "",
                            teamName = item.team?.name ?: "",
                            played = item.all?.played ?: 0,
                            win = item.all?.win ?: 0,
                            draw = item.all?.draw ?: 0,
                            lose = item.all?.lose ?: 0,
                            points = item.points ?: 0
                        )
                    }
                }
            }
        )
    )

    viewModel.addTournamentItem(
        Category(
            title = "Clean Sheets",
            icon = Icons.Default.CleaningServices,
            onClick = {},
            content = {
                TopTeamsClean(
                    rank = 1,
                    logo = team.team?.logo ?: "",
                    teamName = team.team?.name ?: "",
                    played = team.fixtures?.played?.total ?: 0,
                    cleanSheets = team.cleanSheet?.total ?: 0
                )
            }
        )
    )
    // 其他分类项添加逻辑...
}

修改FetchData,传递ViewModel实例:

@Composable
fun FetchData(
    mainViewModel: MainViewModel = hiltViewModel(),
    tournamentViewModel: TournamentStateViewModel = viewModel() // 获取统一实例
) {
    when(val standingsState = mainViewModel.pLStandings.collectAsState().value) {
        is PLStandingsState.Empty -> Text(text = "暂无数据")
        is PLStandingsState.Loading -> Text(text = "加载中...")
        is PLStandingsState.Error -> Text(text = standingsState.message)
        is PLStandingsState.Success -> {
            when(val statsState = mainViewModel.leagueStatsState.collectAsState().value) {
                is LeagueStatsState.Empty -> Text(text = "暂无数据")
                is LeagueStatsState.Loading -> Text(text = "加载中...")
                is LeagueStatsState.Error -> Text(text = statsState.message)
                is LeagueStatsState.Success -> {
                    GetData(
                        team = statsState.teamData,
                        rankList = standingsState.data,
                        viewModel = tournamentViewModel // 传入统一的ViewModel
                    )
                }
            }
        }
    }
}

2. 修复数据集合与内容渲染问题

  • 替换空集合:把ArrayList(3)改成包含有效索引的集合(比如listOf(0,1,2)),确保forEach能执行。
  • 正确传递Composable内容:Category的内容参数应该是@Composable ()->Unit类型的lambda,而不是forEach的执行结果,用content = { ... }包裹子组件。
  • 空安全处理:用?.let和?:避免空指针,不要直接用!!强制解包。

3. 修正预览函数逻辑

预览函数不会触发API请求,直接添加模拟数据来预览UI:

@Preview
@Composable
fun TabSyncComposePreview() {
    val viewModel: TournamentStateViewModel = viewModel()
    // 添加模拟分类数据
    viewModel.addTournamentItem(
        Category(
            title = "Standings",
            icon = Icons.Default.TableRows,
            onClick = {},
            content = {
                TopTeamsPoints(1, "https://example.com/logo.png", "Team A", 10, 6, 2, 2, 20)
                TopTeamsPoints(2, "https://example.com/logo.png", "Team B", 10, 5, 3, 2, 18)
            }
        )
    )

    val list = viewModel.tournamentItemList
    if (list.isNotEmpty()) {
        TabSyncComposeScreen(list)
    } else {
        Text(text = "暂无数据")
    }
}

4. 优化ViewModel状态暴露

简化ViewModel,直接暴露mutableStateListOf,确保UI能自动感知集合变化:

class TournamentStateViewModel: ViewModel() {
    val tournamentItemList = mutableStateListOf<Category>()

    fun addTournamentItem(item: Category){
        tournamentItemList.add(item)
    }
}

额外建议

  • 把API数据处理逻辑移到ViewModel中,Composable只负责状态观察和UI渲染,避免在UI层直接修改数据。
  • 用LaunchedEffect触发一次性的API请求,确保请求只在组件初始化时执行。

内容的提问来源于stack exchange,提问作者Mahmoud Nabil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 18:26:07