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
相关产品推荐
相关产品推荐

