Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting Header information with RXJava and Retrofit

I'm trying to convert my app which currently uses Retrofit, to use RX Java. In order to handle Pagination, I traditionally was grabbing the nextPage URL from the response headers.

@Override
    public void success(Assignment assignment, Response response) {
        response.getHeaders(); // Do stuff with header info
}

However, since switching to RX Java, i'm not sure how to get the response information from my retrofit call.

   @GET("/{item_id}/users")
    Observable<List<Objects>> getObjects(@Path("object_id") long object_id);

    @GET("/{next}")
    Observable<List<Objects>> getNextPageObjects(@Path("next") String nextURL);

Is there a way to have my retrofit calls to return my header information along with my Typed objects?

like image 382
user3169791 Avatar asked Nov 10 '14 19:11

user3169791


People also ask

What is the difference between RxJava and retrofit?

Rx gives you a very granular control over which threads will be used to perform work in various points within a stream. To point the contrast here already, basic call approach used in Retrofit is only scheduling work on its worker threads and forwarding the result back into the calling thread.

What is RxJava and RxAndroid?

RxAndroid is a RxJava for Android extension that is only used in Android applications. RxAndroid added the Android-required Main Thread. We will need the Looper and Handler for Main Thread execution in order to work with multithreading in Android. Note: AndroidSchedulers are provided by RxAndroid.

How does RxJava work internally?

RxJava is a Java VM implementation of ReactiveX a library for composing asynchronous and event-based programs by using observable sequences. The building blocks of RxJava are Observables and Subscribers. Observable is used for emitting items and Subscriber is used for consuming those items.


2 Answers

You can use

Observable<Response>

as return type to get the response details

@GET("/{item_id}/users")
Observable<Response> getObjects(@Path("object_id") long object_id);

@GET("/{next}")
Observable<Response>getNextPageObjects(@Path("next") String nextURL);

This is how the Response object would look like

enter image description here

You would have to then parse the headers and body from the observable

serviceClass.getNextPageObjects("next").flatMap(new Func1<Response, Observable<List<Objects>>() {
    @Override
    public Observable<AuthState> call(Response response) {
         List<Header> headers = response.getHeaders();
         GsonConverter converter = new GsonConverter(new Gson());
         // you would have to change this to convert the objects to list
         List<Objects> list = converter.fromBody(response.getBody(),
                            YourClass.class);

        return Observable.from(list);
    }

}
like image 117
rahulrv Avatar answered Oct 19 '22 00:10

rahulrv


Let me spoiler this. You could intercept request and response as of OkHttp-2.2. As on OkHttp wiki says interceptors will not work in Retrofit with OkUrlFactory. You need to provide your Client implementation to execute Retrofit requests on this custom Client and directly on OkHttp

Unfortunately, it is not out yet (soon).

public class ResponseHeaderInterceptor implements Interceptor {
  public interface ResponseHeaderListener{
     public void onHeadersIntercepted(Headers headers);
  }
  private ResponseHeaderListener mListener;
  public ResponseHeaderInterceptor(){};
  public ResponseHeaderInterceptor(ResponseHeaderListener listener){
     mListener = listener;
  }
  @Override public Response intercept(Chain chain) throws IOException {
    Response response = chain.proceed(chain.request());
    if(mListener != null){
       mListener.onHeadersIntercepted(response.headers());
     }
    return response;
  }

Usage:

ResponseHeaderListener headerListener = new ResponseHeaderListener(){
 @Override
 public void onHeadersIntercepted(Headers headers){
     //do stuff with headers
 }
};
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.interceptors().add(new ResponseHeaderInterceptor(headerListener));
RestAdapter.Builder restAdapterBuilder = new RestAdapter.Builder();
restAdapterBuilder.setClient(new OkHttpClient22(okHttpClient));

This is application interceptor and will be called only once.

Please note that I did all this by logic, I still don't have OkHttp-2.2. Just read about it here. I'll remove some of this text when 2.2 is latest jar.

Alternatively, you can try to create custom client and with one interface deliver the response:

public class InterceptableClient extends OkClient {
    private ResponseListener mListener;
    public interface ResponseListener{
        public void onResponseIntercepted(Response response);
    }
    public InterceptableClient(){};
    public InterceptableClient(ResponseListener listener){
        mListener = listener;
    }
    @Override
    public retrofit.client.Response execute(Request request) throws IOException {
        Response response =  super.execute(request);
        if(mListener != null) //runs on the executor you have provided for http execution
            mListener.onResponseIntercepted(response);
        return response;
    }
}

Edit: OkHttp 2.2 has been released.

like image 3
Nikola Despotoski Avatar answered Oct 19 '22 01:10

Nikola Despotoski