2014-01-21 48 views
3

我正在编写一个整洁的Android应用程序与API进行交互,这遵循Google Android用户体验。StackExchange API处理与改造

该应用程序将使用Retrofit(使REST-api机制更容易)。

现在,我创建了与每个​​API调用相对应的Java类。

例如,Site.java类处理该/sites API以这种方式:

此被冷凝为简洁:

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>集合无论如何,这可能同样适用于其他对象,如Question,Answer等。

在Chrome浏览器下测试Postman扩展后,我观察到以下情况,这是一个绊脚石,无论使用哪种REST-api,都会返回通用包装,但是JSON输出中的items字段在这种情况下包含Site的数组。

我推断,这有一个在未返回公用包装纸领域,名为type这里的想法是要骗一点点稍后...和,因为它不是过滤器,这意味着一部分具有经由/filter/create API来创建一个新的过滤器和应用,作为调用到改造的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调用。

此代码是从StackOverflow上的问题改编,

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 
     } 
    } 

已经摆脱,如何解决这个绊脚石的想法。

我,在理论上,它改写与创造型Site的列表一起返回改造的Response对象,手动解析每个JSON对象,它不觉得累赘和啰嗦每个API返回的对象。

我这样做是错误的方式,还是使用Retrofit库将我的期望设置得过高?

回答

3

当灯泡瞬间熄灭时,对这个问题的回答非常简单。

我意识到,项目的列表可以指任何物体取决于API调用stackexchange.com网站,所以这意味着类的当JSON的items反序列化时,必须使用这些。

该解决方案相当简单。

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! 
    } 
}); 

清洁,优雅和简单,并没有搞乱改造的魔法内脏。

希望这会帮助那些发现自己处于类似的困境,我经历过的人。

享受。

+0

问题:每次获取改造响应时,我们都必须根据我们的响应创建CommonSEWrapper.java类?这是一个好方法,或者我们可以使用http://stackoverflow.com/a/26555618/2382964这个答案来逐个解析JSON。 –