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

如何在Kotlin的Retrofit中将多个JSON对象转为数组并适配RecyclerView

问题:在Kotlin+Retrofit中解析键为ID的JSON对象为数组,用于RecyclerView展示

我需要在RecyclerView中展示两支球队的球员列表,但接口返回的球员数据是以JSON对象(键为球员ID)的形式存在,而非标准JSON数组。接口返回的示例数据如下:

"Teams":{
    "4":{
        "Name_Full":"India",
        "Name_Short":"IND",
        "Players":{
            "3852":{
                "Position":"1",
                "Name_Full":"Rohit Sharma",
                "Iscaptain":true,
                "Batting":{
                    "Style":"RHB",
                    "Average":"47.88",
                    "Strikerate":"88.46",
                    "Runs":"7806"
                },
                "Bowling":{
                    "Style":"OB",
                    "Average":"64.37",
                    "Economyrate":"5.21",
                    "Wickets":"8"
                }
            },
            "3722":{
                "Position":"2",
                "Name_Full":"Shikhar Dhawan",
                "Batting":{
                    "Style":"LHB",
                    "Average":"45.36",
                    "Strikerate":"93.59",
                    "Runs":"5172"
                },
                "Bowling":{
                    "Style":"OB",
                    "Average":"0",
                    "Economyrate":"0",
                    "Wickets":"0"
                }
            }
        }
    }
}

解决方案

方法1:自定义Gson TypeAdapter自动转换

适合希望在解析阶段直接将对象转成List的场景,无需后续手动处理。

1. 定义对应的数据类

写出匹配JSON结构的数据类,通过注解指定Players字段使用自定义解析器:

data class TeamResponse(
    val Teams: Map<String, Team>
)

data class Team(
    val Name_Full: String,
    val Name_Short: String,
    @JsonAdapter(PlayerListTypeAdapter::class)
    val Players: List<Player>
)

data class Player(
    val Position: String,
    val Name_Full: String,
    val Iscaptain: Boolean?,
    val Batting: BattingStats,
    val Bowling: BowlingStats
)

data class BattingStats(
    val Style: String,
    val Average: String,
    val Strikerate: String,
    val Runs: String
)

data class BowlingStats(
    val Style: String,
    val Average: String,
    val Economyrate: String,
    val Wickets: String
)

2. 编写TypeAdapter实现对象转List

创建PlayerListTypeAdapter,负责将JSON对象解析为List<Player>,同时按Position排序保证展示顺序:

class PlayerListTypeAdapter : TypeAdapter<List<Player>>() {
    override fun write(out: JsonWriter, value: List<Player>) {
        // 无需序列化可留空,如需序列化自行实现逻辑
    }

    override fun read(`in`: JsonReader): List<Player> {
        val playerMap = mutableMapOf<String, Player>()
        val gson = Gson()
        
        `in`.beginObject()
        while (`in`.hasNext()) {
            val playerId = `in`.nextName()
            val player = gson.fromJson(`in`, Player::class.java)
            playerMap[playerId] = player
        }
        `in`.endObject()
        
        return playerMap.values.sortedBy { it.Position.toInt() }
    }
}

3. 配置Retrofit使用自定义Gson

构建Retrofit实例时注册自定义TypeAdapter:

val customGson = GsonBuilder()
    .registerTypeAdapter(List::class.java, PlayerListTypeAdapter())
    .create()

val retrofit = Retrofit.Builder()
    .baseUrl("你的接口基础地址")
    .addConverterFactory(GsonConverterFactory.create(customGson))
    .build()

调用接口后,Team中的Players直接是List,可直接传给RecyclerView的Adapter。


方法2:解析为Map后手动转List

不想自定义TypeAdapter时,可直接将Players解析为Map<String, Player>,获取数据后手动转换:

1. 修改数据类

将Team中的Players改为Map类型:

data class Team(
    val Name_Full: String,
    val Name_Short: String,
    val Players: Map<String, Player>
)

2. 接口回调中处理转换

在Retrofit回调里把Map值转成List并排序:

apiService.getTeamData().enqueue(object : Callback<TeamResponse> {
    override fun onResponse(call: Call<TeamResponse>, response: Response<TeamResponse>) {
        response.body()?.let { teamResp ->
            val allPlayers = mutableListOf<Player>()
            teamResp.Teams.values.forEach { team ->
                val sortedPlayers = team.Players.values.sortedBy { it.Position.toInt() }
                allPlayers.addAll(sortedPlayers)
            }
            recyclerView.adapter = PlayerAdapter(allPlayers)
        }
    }

    override fun onFailure(call: Call<TeamResponse>, t: Throwable) {
        // 处理请求失败逻辑
    }
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 07:10:41