我正在编写一个简洁的Android应用程序以与API交互,这遵循了Google Android用户的体验.
该应用程序将使用Retrofit(使REST-api机制更容易).
现在,我创建了与每个API调用相对应的Java类.
例如,以以下方式处理/ sites API的Site.java类:
为简洁起见,这是简洁的:
public class Site{
@SerializedName("api_site_parameter") String mApiSiteParameter = "";
// snip
}
该接口以这种方式进行连接,称为ISites.java
public interface ISites{
@GET("/sites")
public void getAllSites(@Query("filter") String filterName,
Callback<List<Site>> cbAllSites);
}
最大的问题是,由于使用了通用包装器,我如何才能使Retrofit返回到List< Site>.无论如何,这可能同样适用于其他对象,例如“问题”,“答案”等.
在Chrome下使用Postman扩展程序进行测试后,我观察到以下内容,这是一个绊脚石,无论使用哪种REST-api,响应中都会返回通用包装器,但是JSON输出中的items字段包含数组在这种情况下的网站数量.
我推断出,在普通包装器中有一个未返回的字段,称为type.这里的想法是稍后再作弊…,因为它不是过滤器的一部分,这意味着必须创建一个新的过滤器通过/ filter / create API并将其作为对Retrofit的RestAdapter调用的调用的一部分进行应用,如下所示:
RestAdapter ra = new RestAdapter.Builder()
.setServer("http://api.stackexchange.com/2.1")
.setLogLevel(LogLevel.FULL)
.build();
ISites sites = ra.create(ISites.class);
sites.getAllSites("my_commonwrapper_filter", Callback<Site>(){
@Override
public void failure(RetrofitError argRetrofitError){
}
@Override
public void success(List<Site> sites, Response response){
}
});
在研究了Gson的自定义TypeAdapterFactory(其值为answered here on SO)之后,我是否在这里遗漏了一些东西,这是我到目前为止所拥有的.
创建了一个名为SEWrapper.java的类,它像这样:
public class SEWrapper{
@SerializedName("items") List<Class ?> mListItems;
@SerializedName("type") String mJsonObjType;
}
在Site.java源代码中更改为使用SEWrapper而不是Site,并修改了REST调用.
这段代码改编自*上的问题,
private class SEWrapperTypeAdapterFactory extends CustomizedTypeAdapterFactory<SEWrapper> {
private SEWrapperTypeAdapterFactory() { super(SEWrapper.class); }
@Override
protected void beforeWrite(SEWrapper source, JsonElement toSerialize) {
// Ignored for now as all this is Read Only operation!
}
@Override
protected void afterRead(JsonElement deserialized) {
String typeOfJsonObj = deserialized.getAsJsonObject().get("type").getAsString();
if (typeOfJsonObj.equalsIgnoreCase("site")){
JsonArray jSiteArray = deserialized.getAsJsonObject().get("items").getAsJsonArray();
// Convert that to List<Site> type which I cannot figure out
}
}
关于如何解决这个绊脚石的想法不多.
从理论上讲,我可以将其重写以返回Retrofit的Response对象,并手动解析每个JSON对象以及创建该类型的Site列表,对于返回的每个API对象,它确实很麻烦且冗长.
我是用错误的方式这样做还是对Retrofit库设置了过高的期望?
解决方法:
当灯泡瞬间消失时,这个问题的答案非常简单.
我意识到,根据对stackexchange.com网站的API调用,项目列表可以引用任何对象,因此这意味着在对JSON的项目进行反序列化时应使用的一种类.
解决方案非常简单.
CommonSEWrapper.java:
public class CommonSEWrapper<T>{
// snip
@SerializedName("items") List<T> mListItems;
// snip
}
然后,要申请Site对象,站点的REST API的接口将最终变为ISites.java:
public interface ISites{
@GET("/sites")
public void getAllSites(@Query("filter") String filterName,
Callback<CommonSEWrapper<Site>> cbAllSites);
}
最后,通过Retrofit执行REST如下所示:
RestAdapter ra = new RestAdapter.Builder()
.setServer("http://api.stackexchange.com/2.1")
.build();
ISites sites = ra.create(ISites.class);
ra.getAllSites("", new Callback<CommonSEWrapper<Site>>(){
@Override
public void failure(RetrofitError argRetrofitError){
}
@Override
public void success(CommonSEWrapper<Site> sites, Response response){
// sites is filled in, just like magic!
}
});
干净,优雅,简单,而且不会与Retrofit的魔法内乱交织.
希望这会帮助其他处于类似困境的人.
请享用.