项目场景
会有这种情况,需要获取到服务端返回的字符串,再根据返回的结果进一步处理,而不是直接获取到定义好的对象。
问题描述
如果将接口定义为如下情况,当接口返回结果为大括号开头,可能会遇到报错:Expected a string but was BEGIN_OBJECT at line 1 column 2 path $
interface Service {
@POST("/test")
suspend fun test(@Body body: RequestBody): String
}
解决方案
这里提供两种解决方案供参考:
方案1:
将返回结果改为 JsonObject
interface Service {
@POST("/test")
suspend fun test(@Body body: RequestBody): JsonObject
}
方案2:
替换GsonConverterFactory(这个方案也很简单,分以下三步)
Okhttp获取请求后,通过 GsonConverterFactory 的 responseBodyConverter 获取到GsonResponseBodyConverter对象,GsonResponseBodyConverter的convert方法负责将获取到的结果转换为想要的对象。
第一步:我们这里只需要 GsonConverterFactory 和 GsonResponseBodyConverter 复制一份出来,修改一个喜欢的名字,比如我这里定义为 MyGsonConverterFactory 和 MyGsonResponseBodyConverter。
第二部:修改MyGsonResponseBodyConverter的convert方法如下:
final class MyGsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public RequestBody convert(T value) throws IOException {
String response = value.string();
try {
T result = gson.fromJson(response, type);
return result;
} catch (JsonSyntaxException e) {
// 解析出错,如果是String类型直接返回
if (type instanceof Class) {
Class<?> clazz = (Class<?>) type;
if (clazz == String.class) {
return (T) response;
}
}
throw e;
}
}
}
第三部:
实例化Service的时候记得替换成我们定义的ConverterFactory
Retrofit
.Builder()
.baseUrl(hostUrl)
.client(okHttpClient)
.addConverterFactory(MyGsonConverterFactory.create()) // 自定义的ConvertFactory