我正在尝试使用Google的GithubBrowserSample here作为MVVM架构来构建应用程序。该示例使用Github API来检索数据。 API返回对象列表,如下所示:
[
{
"login": "obenland",
"id": 1398304,
"node_id": "MDQ6VXNlcjEzOTgzMDQ=",
"site_admin": false,
...
"contributions": 234
},
{
"login": "davidakennedy",
"id": 1473618,
"node_id": "MDQ6VXNlcjE0NzM2MTg=",
"avatar_url": "https://avatars1.githubusercontent.com/u/1473618?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/davidakennedy",
"html_url": "https://github.com/davidakennedy",
...
"type": "User",
"site_admin": false,
"contributions": 95
},
]
但是我的App API会像这样在JSONObject中返回一个列表:
{"data":[{"id":41,"title":"Hey",...]}
因此Retrofit无法通过原因错误来解析响应:Expected BEGIN_ARRAY but was BEGIN_OBJECT
API调用为:
@GET("user/photos")
LiveData<ApiResponse<List<Photo>>> getPhotos();
这是ApiResponse类:
public class ApiResponse<T> {
private static final Pattern LINK_PATTERN = Pattern
.compile("<([^>]*)>[\\s]*;[\\s]*rel=\"([a-zA-Z0-9]+)\"");
private static final Pattern PAGE_PATTERN = Pattern.compile("\\bpage=(\\d+)");
private static final String NEXT_LINK = "next";
public final int code;
@Nullable
public final T body;
@Nullable
public final String errorMessage;
@NonNull
public final Map<String, String> links;
public ApiResponse(Throwable error) {
code = 500;
body = null;
errorMessage = error.getMessage();
links = Collections.emptyMap();
}
public ApiResponse(Response<T> response) {
code = response.code();
if(response.isSuccessful()) {
body = response.body();
errorMessage = null;
} else {
String message = null;
if (response.errorBody() != null) {
try {
message = response.errorBody().string();
} catch (IOException ignored) {
Timber.e(ignored, "error while parsing response");
}
}
if (message == null || message.trim().length() == 0) {
message = response.message();
}
errorMessage = message;
body = null;
}
String linkHeader = response.headers().get("link");
if (linkHeader == null) {
links = Collections.emptyMap();
} else {
links = new ArrayMap<>();
Matcher matcher = LINK_PATTERN.matcher(linkHeader);
while (matcher.find()) {
int count = matcher.groupCount();
if (count == 2) {
links.put(matcher.group(2), matcher.group(1));
}
}
}
}
这是LiveDataCallAdapterFactory:
public class LiveDataCallAdapterFactory extends CallAdapter.Factory {
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != LiveData.class) {
return null;
}
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
if (rawObservableType != ApiResponse.class) {
throw new IllegalArgumentException("type must be a resource");
}
if (! (observableType instanceof ParameterizedType)) {
throw new IllegalArgumentException("resource must be parameterized");
}
Type bodyType = getParameterUpperBound(0, (ParameterizedType) observableType);
return new LiveDataCallAdapter<>(bodyType);
}
}
这就是改造的构建方式:
return new Retrofit.Builder()
.baseUrl("http://api.*******.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(new LiveDataCallAdapterFactory())
.build()
.create(GithubService.class);