如何创建返回Map的自定义Moshi JsonAdapter并适配Retrofit
实现Moshi适配器将API返回的JSON转为Map<String, String>并配合Retrofit使用
完全可以实现你的需求,以下是修正后的完整方案:
一、修正自定义Moshi适配器
你的适配器目标是处理Map<String, String>类型,无需绑定到多余的Countries类。如果不需要将Map序列化为JSON,可以直接删除无用的@ToJson方法;若后续需要序列化,可保留并修正实现:
class CountriesAdapter { @FromJson fun fromJson(reader: JsonReader): Map<String, String> { val countries = mutableMapOf<String, String>() with(reader) { beginObject() while (hasNext()) { countries[nextName()] = nextString() } endObject() } return countries } // 可选:如果需要将Map序列化为JSON,保留此方法;否则可删除 @ToJson fun toJson(writer: JsonWriter, map: Map<String, String>) { with(writer) { beginObject() map.forEach { (key, value) -> name(key) value(value) } endObject() } } }
二、修正Retrofit API接口定义
API接口方法应直接返回Call<Map<String, String>>,而非Call<Countries>,让Retrofit明确要解析的目标类型:
interface APIInterface { @GET("path/to/your/countries/api") // 替换为实际的API路径 fun getCountries(): Call<Map<String, String>> }
三、修正Retrofit初始化与调用
移除无用的Countries数据类,Retrofit会通过Moshi自动将JSON解析为Map,无需手动调用适配器方法:
val moshi = Moshi.Builder() .add(CountriesAdapter()) .addLast(KotlinJsonAdapterFactory()) .build() val retrofit = Retrofit.Builder() .baseUrl("https://flagcdn.com") .addConverterFactory(MoshiConverterFactory.create(moshi)) .build() .create(APIInterface::class.java) retrofit.getCountries().enqueue(object : Callback<Map<String, String>> { override fun onResponse(call: Call<Map<String, String>>, response: Response<Map<String, String>>) { if (response.isSuccessful) { // 直接获取解析后的Map val countriesMap = response.body() countriesMap?.let { // 这里处理Map数据,比如赋值给LiveData _countries.value = it } } } override fun onFailure(call: Call<Map<String, String>>, t: Throwable) { // 处理请求失败逻辑 } })
关键说明
- Moshi会自动匹配
@FromJson方法处理Map<String, String>类型的解析,无需手动调用适配器的fromJson方法。 - 移除
Countries数据类是因为我们不需要将JSON映射到固定实体类,直接转为键值对Map即可满足需求。 - 当前实现适配你提供的API格式(所有值均为String类型),若后续API返回非String值,需在适配器中添加类型判断逻辑。
内容的提问来源于stack exchange,提问作者Daniel Bertoldi
相关产品推荐
相关产品推荐

