2016-03-15 3 views
2

Я пишу библиотеку для REST API. Библиотеке придется как можно больше скрыть от пользователя внутреннюю сложность API.Android Retrofit2: как передать параметры запроса запроса на ответ?

Я полагаюсь на retrofit2, сконфигурированный для использования RxJava, чтобы обернуть ответы и GSon для их анализа.

Я использую retrofit для службы REST.

@GET("search") 
Observable<SearchResult> search(@Query("q") String query); 

@GET("search") 
Observable<SearchResult> search(@QueryMap Map<String, String> params); 

@GET("search") 
Observable<SearchResult> searchNext(@Query("q") String query, @Query("startKey") String startKey); 

@GET("search") 
Observable<SearchResult> searchNext(@QueryMap Map<String, String> params, @Query("startKey") String startKey); 

Поиск REST службы возвращающие JSON

{ 
    "count": 2334, 
    "nextBatchKey": "SADjdfsahoi023451sadfjlskdfj02134512", 
    "results": [ .... ] 
} 
  • общее количество результата
  • ключ будет использоваться для получения следующей партии из списка
  • фактический массив от результатов

Для получения в следующей партии услуга должна быть вызвана снова с теми же параметрами и возвращаемым ключом.

Например, предположим, что делает поиск для q=foo и limit=20: The Rest API будет возвращать результаты, соответствующие строки Foo порционный в сегментах 20 результатов каждого. Чтобы получить следующую партию, мне нужно будет создать другой запрос с теми же двумя параметрами: q=foo и limit=20, добавив startKey=<the next batch key>.

Я хочу/должен скрывать от пользователя библиотеки эти внутренние механизмы.

Внутри моей библиотеки я инициализировать переоснащения так:

Retrofit retrofit = new Retrofit.Builder() 
    .client(okHttpClient) // added interceptors 
    .baseUrl(baseUrl) // my base url 
    .addConverterFactory(GsonConverterFactory.create(gson)) // custom type adapter factory 
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
    .build(); 

Он генерирует сервис для моего интерфейса и использовать Gson разобрать ответ оборачивать его RxJavaObservable.

Тогда я получить услугу:

MyService service = retrofit.create(MyService.class) 

Обратите внимание, что я не пишу код этой службы, поскольку Модифицированная работает он генерирует сервис автоматически, используя свой интерфейс (MyService) аннотаций.

Из библиотеки точки зрения пользователя все это скрыто, он будет просто получить услугу и использовать его как это:

// obtain the service 
MyService service = MyLibrarySDK.getService(context); 
// perform the search operation 
Observable<SearchResult> resultObservable = 
    service.search(params); 

Я хочу, чтобы разработчик, используя свою библиотеку, чтобы иметь возможность получить следующую партию, как это :

// then later result == the SearchResult 
Observable<SearchResult> nextBatch = 
    result.searchNext(); 

Звонок searchNext() не принимает никаких параметров. Это означает, что объект SearchResult, созданный мной в предыдущем вызове, должен знать, какие параметры использовать при использовании метода searchNext(Map parameters, String key).

Если пользователь выполняет поисковый вызов с q=foo, эта информация не будет получена в ответ. И мне это нужно.

С момента создания службы я не знаю, как я могу перехватить параметры метода, переданные с вызовом service.search().

Единственная идея, которую я должен был решить эту проблему заключается в использовании OkHttp перехватчика, разместить параметры запроса карты в ThreadLocal, а затем использовать пользовательские GsonTypeAdapter, чтобы ввести эти параметры в SearchResult объекта.

Это решение должно технически работать, но я думаю, что это уродливо. Кроме того, перехватчик будет запускаться для любого метода REST API, но мне это нужно только для поисковых запросов.

У вас есть лучшая/креативная/элегантная идея?

+0

Вы бы не получать параметры запроса из модели данных? Вы делаете что-то вроде этого: https://github.com/codepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews? – Krishnaraj

+0

@ Кришнарай был моим вопросом плохо написанным? потому что вы спрашиваете, почему я думаю, что вы этого не поняли. Я могу улучшить вопрос, если вы скажете мне, где это путают –

+0

@ Krishnaraj в любом случае, предполагая, что с «моделью данных» вы подразумеваете ответ json для поиска: он содержит только результаты, общее количество и ключ для получения следующей партии. Таким образом, если мне нужно получить следующую партию, мне нужен этот ключ и все параметры, используемые для первого вызова. Я хочу сделать это прозрачным в API-интерфейсе клиента, поэтому мне нужен способ передачи этих параметров. –

ответ

0

Не думайте, что у вас должно быть searchNext() на result, а скорее на service.

попробовать что-то, как показано ниже:

MyService.java

public class MyService { 
    RestClient.GitApiInterface service = RestClient.getClient(); 
    String query; 
    Observable<GitResult> resultObservable; 

    public Observable<GitResult> getUsersByName(String query) { 
     this.query = query; 
     resultObservable = service.getUsersByName(query, 0).cache(); 
     return resultObservable; 
    } 

    public Observable<GitResult> searchNext() { 
     Observable nextResultObservable = resultObservable 
       .flatMap(new Func1<GitResult, Observable<?>>() { 
        @Override 
        public Observable<?> call(GitResult gitResult) { 
         return service.getUsersByName(query, gitResult.getNextPage()); 
        } 
       }); 

     return nextResultObservable; 
    } 
} 

Использование

final MyService service = new MyService(); 
// First load 
service.getUsersByName("tom"); 
// consecutive calls 
service.searchNext(); 

Пример приложения - https://gitlab.com/wizardkrishna/retrofit2-sample

Ссылки
Consuming REST API using Retrofit2
Observable Caching

+0

Почему вы считаете, что метод SearchResult.next() плох? –

+1

SearchResult - это, вероятно, класс модели, привязка вызова службы к нему не кажется хорошей идеей. – Krishnaraj

+0

Я думаю, что сервис с государством даже худший :) –

Смежные вопросы