How Retrieve Response Body with RxAndroid and Retrofit 2?
Try something like this:
import okhttp3.ResponseBody;
import retrofit2.Response;
@GET("/whatever")
Observable<Response<ResponseBody>> getWhatever();
Edit: Don't forget you have to specify the adapter for RxJava:
new Retrofit.Builder()
...
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build()
.create(Api.class);
Bryan
Professional software engineer and game development hobbyist.
Updated on July 24, 2022Comments
-
Bryan almost 2 years
I am using Retrofit 2 (beta 4), and I was looking to move from using the standard
Call
response to the RxAndroidObservable
response. I was successful in switching most of my calls with a simple swap fromCall<List<ExampleObject>>
toObservable<List<ExampleObject>>
. A few of my calls useCall<okhttp3.ResponseBody>
, which works great, but when I swapped outCall
, I was met with an error:03-03 15:21:44.237 27333-27333/com.example.app E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.app, PID: 27333 java.lang.IllegalArgumentException: Unable to create call adapter for rx.Observable<okhttp3.ResponseBody> for method AuthenticationService.getLoginForm at retrofit2.Utils.methodError(Utils.java:119) at retrofit2.MethodHandler.createCallAdapter(MethodHandler.java:52) at retrofit2.MethodHandler.create(MethodHandler.java:25) at retrofit2.Retrofit.loadMethodHandler(Retrofit.java:164) at retrofit2.Retrofit$1.invoke(Retrofit.java:145) at java.lang.reflect.Proxy.invoke(Proxy.java:393) at $Proxy6.getLoginForm(Unknown Source) at com.example.app.ui.fragment.LoginFragment.login(LoginFragment.java:214) at com.example.app.ui.fragment.LoginFragment.lambda$onContinue$1(LoginFragment.java:168) at com.example.app.ui.fragment.LoginFragment.access$lambda$1(LoginFragment.java) at com.example.app.ui.fragment.LoginFragment$$Lambda$4.onClick(Unknown Source) at android.view.View.performClick(View.java:5204) at android.view.View$PerformClick.run(View.java:21153) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for rx.Observable<okhttp3.ResponseBody>. Tried: * retrofit2.ExecutorCallAdapterFactory at retrofit2.Retrofit.nextCallAdapter(Retrofit.java:230) at retrofit2.Retrofit.callAdapter(Retrofit.java:194) at retrofit2.MethodHandler.createCallAdapter(MethodHandler.java:50) ... 18 more
The reason I am using the
ResponseBody
instead of another object as usual, is because in these cases I need to parse HTML, and as far as I know, there is no Retrofit converter for an HTML parser. I know I probably could create one on my own, but I would rather not for the small amount of HTML I have to parse.My question is why doesn't the Retrofit 2 RxJava Adapter support
ResponseBody
when Retrofit 2 itself does? Is there another way I can obtain the response string from anObservable
?
My Service:
public interface AuthenticationService() { @GET("cas/login") Observable<Response<ResponseBody>> login(); }
Relevant Retrofit code:
public static Retrofit getRetrofit() { if(mRetrofit == null) { return new Retrofit.Builder() .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create(getGson())) .client(getOkHttpClient()) .build(); } return mRetrofit; } public static AuthenticationService getAuthenticationService() { return getRetrofit().create(AuthenticationService.class); }
Response attempt:
private void login() { RestClient.getAuthenticationService().login() .observeOn(ASchedulers.newThread()) .subscribeOn(AndroidSchedulers.mainThread()) .doOnNext(this::onLoginResponse); } private void onLoginResponse(Response<ResponseBody>> response) { try { parseResponse(response.body().string()); } catch (IOException) { Timber.w(throwable, "Failed to login"); } }
New stack trace:
03-03 16:14:57.848 26866-26866/com.example.app E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.app, PID: 26866 java.lang.IllegalArgumentException: Unable to create call adapter for rx.Observable<retrofit2.Response<okhttp3.ResponseBody>> for method AuthenticationService.getLoginForm at retrofit2.Utils.methodError(Utils.java:119) at retrofit2.MethodHandler.createCallAdapter(MethodHandler.java:52) at retrofit2.MethodHandler.create(MethodHandler.java:25) at retrofit2.Retrofit.loadMethodHandler(Retrofit.java:164) at retrofit2.Retrofit$1.invoke(Retrofit.java:145) at java.lang.reflect.Proxy.invoke(Proxy.java:393) at $Proxy3.getLoginForm(Unknown Source) at com.example.app.ui.fragment.LoginFragment.login(LoginFragment.java:206) at com.example.app.ui.fragment.LoginFragment.lambda$onContinue$1(LoginFragment.java:160) at com.example.app.ui.fragment.LoginFragment.access$lambda$1(LoginFragment.java) at com.example.app.ui.fragment.LoginFragment$$Lambda$4.onClick(Unknown Source) at android.view.View.performClick(View.java:5204) at android.view.View$PerformClick.run(View.java:21153) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for rx.Observable<retrofit2.Response<okhttp3.ResponseBody>>. Tried: * retrofit2.ExecutorCallAdapterFactory at retrofit2.Retrofit.nextCallAdapter(Retrofit.java:230) at retrofit2.Retrofit.callAdapter(Retrofit.java:194) at retrofit2.MethodHandler.createCallAdapter(MethodHandler.java:50) ... 18 more
-
Tudor Luca about 8 yearsPlease post the actual code.
-
Bryan about 8 years@TudorLuca Updated with code
-
Bryan about 8 years@TudorLuca I'm sorry for wasting your time. I found out that I actually was using a Retrofit object (that I should've deleted) that didn't have an RxJavaCallAdapterFactory. I am tearing apart the current code, and it's a bit of a mess. Thank you for you help anyway.
-
tir38 almost 8 years@Bryan can you clarify that last statement?
-
Bryan almost 8 years@tir38 It was a dumb mistake, at the time I was trying to fix some old code. I had accidentally set up two
Retrofit
objects within my code, one with theRxJavaCallAdapterFactory
set up and one without it. I querying the oldRetrofit
object without the adapter factory, which is why I couldn't get anObservable<ResponseBody>
.
-
-
Bryan about 8 yearsTried that, same result :/ I also tried a plain
okhttp3.Respone
, that doesn't work either. -
Bryan about 8 yearsYes, I have the
RxJavaCallAdapterFactory
set up correctly, as my otherObservable<Example>
responses work as expected. -
Tudor Luca about 8 yearsIt won't work with okhttp3.Respone, you need Retrofit's Response.
-
Bryan about 8 yearsI had been using
retrofit2.Response
, along withokhttp3.ResponseBody
(okHttp3 doesn't have aResponse<T>
, just aResponse
). Have you gotten this to work in the past? -
Tudor Luca about 8 yearsMy answer should work just fine. Post the entire code you're using, and the stacktrace you get with my code.
-
Bryan about 8 yearsIt also works with just the
Observable<ResponseBody>
, without the need forResponse<T>
.