1:问题概述
Android Retrofit 请求网络数据,以String(LinkedTreeMap形式返回)形式返回数据.这里是以Any接收的数据.当数据中出现url地址等包含需要转义的字符串时 str转bean的时候出现异常
2: 环境
- retrofit 2.9.0
- converter-gson:2.9.0
- okhttp:4.11.0
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.11.0'
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
api "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
api 'io.reactivex.rxjava3:rxandroid:3.0.2'
api "io.reactivex.rxjava3:rxjava:3.1.5"
数据:
{
"action":"sms_login","api_code":200,"token":"xxx"
"user":{"video_address_suffix":null,
"push_video_add":"rtmp:\/\/push.dev.qiandurebo.com\/qiandulive\/1258",
"push_video_add2":"rtmp:\/\/push.dev.qiandurebo.com\/qiandulive\/1258",
"anchor_rank_id":"4",
"avatar":"https:\/\/imgcdn.dev.qiandurebo.com\/static_data\/uploaddata\/avatar\/1\/1973893.png_t=1721808886&imageMogr2\/thumbnail\/x150","balance":"29861232","beibei_verify":0,"show_verify":"0","birthday":0,"age":""
,....}
}
异常:
com.google.gson.stream.MalformedJsonException: Unterminated object at line 1 column 161 path $.user.push_video_add
3:思路
- MalformedJsonException
json格式异常 - 核心信息
push_video_add字段异常
参考上述信息猜测 包含url等特殊字符 直接使用 Gson().formJson()需要json类型的数据 it.toString()转为Json出了异常,所以 将it.toString() 换为 Gson().toJson(it)
当你用 Retrofit + Gson 这样写:
kotlin
复制编辑
@POST("login")
suspend fun login(@Body body: RequestBody): Any
你返回的是 Any 类型,Gson 会默认把 JSON 对象反序列化为:
| JSON 类型 | Gson 转换类型 |
|---|---|
object {} | LinkedTreeMap |
array [] | ArrayList |
string | String |
number | Double |
boolean | Boolean |
null | null |
LinkedTreeMap.toString() 会生成一个类似这种格式的字符串:
kotlin
复制编辑
{nickname=monkey, gender=1, age=25, user={id=123, token=abc123}}
⚠️ 注意:
这不是合法的 JSON!虽然看起来像 JSON,但有以下几个关键区别:
| 问题项 | 描述 |
|---|---|
| ❌ 键没加引号 | JSON 中键必须是 "key" 格式 |
| ❌ 字符串值没加引号 | 字符串类型的值必须加 "" |
| ✅ 数值是合法的 | 数字/布尔是合法的,但不够明确 |
| ❌ 嵌套对象格式错误 | 嵌套结构缺引号/格式不标准 |
4:方案
经过上边分析 应该是url中的特殊字符在String 中的展示和json中的展示不一样.所以我们将string先转为json再给Gson使用就没问题了
//生效
val responseResult: LoginResponse = gson.fromJson<LoginResponse>(gson.toJson(it), LoginResponse::class.java)
//异常
val responseResult: LoginResponse = gson.fromJson<LoginResponse>(it.toString(), LoginResponse::class.java)