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

KMM项目中Retrofit将JSON转为Kotlin Map失败求助

解决KMM中Retrofit+Gson解析键唯一的JSON对象为Map<String, Currency>的问题

核心解决方案

直接让Retrofit接口返回Map<String, Currency>即可,Gson原生支持这种键为字符串、值为统一结构对象的JSON解析,无需反射或生成冗余子类。以下是具体实现步骤:


1. 定义匹配JSON结构的Currency数据类

确保字段名与API返回的JSON字段完全一致(或用@SerializedName映射):

data class Currency(
    val code: String,
    val alphaCode: String,
    val numericCode: String,
    val name: String,
    val rate: Double,
    val date: String,
    val inverseRate: Double
)

2. 编写正确的Retrofit接口

在KMM公共模块中定义带挂起函数的API接口:

interface ExchangeRateApi {
    @GET("daily/usd.json")
    suspend fun getExchangeRates(): Map<String, Currency>
}

3. 初始化Retrofit与Gson

在公共模块中创建API实例(无需特殊Gson配置,默认规则即可):

fun createExchangeRateApi(): ExchangeRateApi {
    val gson = GsonBuilder().create()
    val retrofit = Retrofit.Builder()
        .baseUrl("http://www.floatrates.com/")
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()
    return retrofit.create(ExchangeRateApi::class.java)
}

4. 调用API并存储到Realm

在Repository或ViewModel中处理数据获取与存储:

// 先定义Realm实体类(公共模块)
class CurrencyRealmObject : RealmObject {
    var key: String = ""
    var code: String = ""
    var alphaCode: String = ""
    var numericCode: String = ""
    var name: String = ""
    var rate: Double = 0.0
    var date: String = ""
    var inverseRate: Double = 0.0
}

// 数据获取与存储逻辑
suspend fun fetchAndStoreRates(realm: Realm) {
    try {
        val ratesMap = createExchangeRateApi().getExchangeRates()
        // 写入Realm
        realm.write {
            ratesMap.forEach { (currencyKey, currency) ->
                copyToRealm(CurrencyRealmObject().apply {
                    this.key = currencyKey
                    this.code = currency.code
                    this.alphaCode = currency.alphaCode
                    this.numericCode = currency.numericCode
                    this.name = currency.name
                    this.rate = currency.rate
                    this.date = currency.date
                    this.inverseRate = currency.inverseRate
                })
            }
        }
    } catch (e: Exception) {
        // 处理网络请求或数据库错误
    }
}

常见问题排查

  • 返回null的原因:
    • 接口定义错误(比如写成返回List<Currency>而非Map)
    • Currency类字段与JSON字段不匹配(比如类型错误,rate写成Float而非Double)
    • 网络请求失败(未添加网络权限)
  • iOS网络权限配置:
    因API使用HTTP协议,需在iOS的Info.plist中添加例外:
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>floatrates.com</key>
            <dict>
                <key>NSIncludesSubdomains</key>
                <true/>
                <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
                <true/>
            </dict>
        </dict>
    </dict>
    
  • Android网络权限:
    在AndroidManifest.xml中添加:
    <uses-permission android:name="android.permission.INTERNET"/>
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 05:52:40