2016-03-03 1 views
7

J'utilise Retrofit 2 (beta 4), et je cherchais à passer de l'utilisation de la réponse standard Call à la réponse RxAndroid Observable. J'ai réussi à passer la plupart de mes appels avec un simple échange de Call<List<ExampleObject>> à Observable<List<ExampleObject>>. Certains de mes appels utilisent Call<okhttp3.ResponseBody>, qui fonctionne très bien, mais quand je troqué Call, je rencontré une erreur:Comment extraire le corps de réponse avec RxAndroid et Retrofit 2?

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 

La raison pour laquelle je me sers du ResponseBody au lieu d'un autre objet, comme d'habitude, parce que dans Dans ces cas, j'ai besoin d'analyser HTML, et pour autant que je sache, il n'y a pas de convertisseur Retrofit pour un analyseur HTML. Je sais que je pourrais probablement en créer un seul, mais je préférerais ne pas utiliser la petite quantité de HTML que j'ai à analyser.

Ma question est pourquoi l'adaptateur Retrofit 2 RxJava ne prend-il pas en charge ResponseBody lorsque Retrofit 2 lui-même le fait? Y a-t-il un autre moyen d'obtenir la chaîne de réponse d'un Observable?


Mon service:

public interface AuthenticationService() { 

    @GET("cas/login") 
    Observable<Response<ResponseBody>> login(); 
} 

pertinentes Code Retrofit:

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

Réponse tentative:

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

Nouvelle trace de la pile:

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 
+1

S'il vous plaît afficher le code réel. –

+0

@TudorLuca Mis à jour avec le code – Bryan

+0

@TudorLuca Je suis désolé de perdre votre temps. J'ai découvert que j'utilisais en fait un objet Retrofit (que j'aurais dû supprimer) qui n'avait pas de RxJavaCallAdapterFactory. Je déchire le code actuel, et c'est un peu le bordel. Merci pour votre aide de toute façon. – Bryan

Répondre

16

Essayez quelque chose comme ceci:

import okhttp3.ResponseBody; 
import retrofit2.Response; 

@GET("/whatever") 
Observable<Response<ResponseBody>> getWhatever(); 

Modifier: Ne pas oublier que vous devez spécifier l'adaptateur pour RxJava:

new Retrofit.Builder() 
      ... 
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
      .build() 
      .create(Api.class); 
+0

Essayé que, même résultat:/J'ai également essayé un 'okhttp3.Respone' plaine, qui ne fonctionne pas non plus. – Bryan

+0

Oui, la fonction 'RxJavaCallAdapterFactory' est correctement configurée, car mes autres réponses' Observable 'fonctionnent comme prévu. – Bryan

+2

Cela ne fonctionnera pas avec okhttp3.Respone, vous avez besoin de la réponse Retrofit. –