2014-01-21 4 views
3

В настоящее время я пишу аккуратное приложение для Android для взаимодействия с API, которое следует за пользователями Google Android.Обработка StackExchange API с помощью дооснащения

Приложение будет использовать Retrofit (чтобы упростить механизмы REST-api).

Теперь я создал классы Java, соответствующие каждому вызову API.

Например, 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 и так далее.

После тестирования с расширением Postman в Chrome я заметил следующее, которое является камнем преткновения, в ответ возвращается общая оболочка, независимо от того, какой REST-api использовать, однако, поле items в выводе JSON , содержит массив 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 
     } 
    } 

Am из идей о том, как обойти этот камень преткновения.

Я мог бы, в теории, переписать его, чтобы вернуться Response объекта при модернизации и вручную разобрать каждый объект JSON наряду с созданием списка этого типа Site, он действительно чувствует себя громоздким и многословен для каждого объекта API вернулся.

Я делаю это неправильно, или я задал свои ожидания немного слишком высоко с помощью библиотеки «Дооснащение»?

ответ

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

и, наконец, выполнение REST с помощью Retrofit будет выглядеть так:

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 один за другим. –