Android Retrofit2:如何将请求查询参数传递给响应?

时间:2016-03-15 14:44:15

标签: android retrofit2

我正在为REST API编写一个库。该库必须尽可能地向用户隐藏API的内部复杂性。

我依赖于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=foolimit=20:REST API将返回匹配字符串 foo 的结果,这些字符串分段为20个结果。要获得下一批,我需要使用相同的两个参数q=foolimit=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解析包含RxJava Observable的响应。

然后我获得了服务:

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中,然后使用自定义Gson TypeAdapter来将这些参数注入SearchResult对象。

这个解决方案应该在技术上有效,但我觉得它很难看。此外,拦截器可以运行REST API的任何方法,但我只需要搜索查询。

你有更好的/有创意/优雅的想法吗?

1 个答案:

答案 0 :(得分:0)

不要认为result上应该有service,而是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();

尝试以下内容:

<强> MyService.java

{{1}}

<强>用法

{{1}}

示例应用 - https://gitlab.com/wizardkrishna/retrofit2-sample

<强>参考
Consuming REST API using Retrofit2
Observable Caching