2016-03-03 10 views
7

Używam Retrofit 2 (beta 4), a ja chciałem przejść od użycia standardowej odpowiedzi Call do odpowiedzi RxAndroid Observable. Udało mi się przełączyć większość połączeń za pomocą prostej zamiany z Call<List<ExampleObject>> na Observable<List<ExampleObject>>. Kilka moich rozmów używać Call<okhttp3.ResponseBody>, który działa świetnie, ale kiedy wyswapowany Call, I spotkałem się z błędem:W jaki sposób pobrać treść odpowiedzi za pomocą RxAndroid i 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 

Powodem Używam ResponseBody zamiast innego obiektu, jak zwykle, ponieważ w w takich przypadkach muszę parsować HTML i, o ile mi wiadomo, nie ma konwertera Retrofit dla parsera HTML. Wiem, że prawdopodobnie mógłbym stworzyć go samemu, ale wolałbym, aby nie była to mała ilość HTML, którą muszę przeanalizować.

Moje pytanie brzmi: dlaczego adapter Retrofit 2 RxJava nie obsługuje ResponseBody, gdy sam Retrofit 2 działa? Czy istnieje inny sposób, w jaki mogę uzyskać ciąg odpowiedzi od Observable?


Moje życzenie:

public interface AuthenticationService() { 

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

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

próba odpowiedzi:

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

Nowy ślad stosu:

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

proszę umieszczać rzeczywisty kod. –

+0

@TudorLuca Zaktualizowany kodem – Bryan

+0

@TudorLuca Przykro mi, że marnujesz swój czas. Dowiedziałem się, że faktycznie używałem obiektu Retrofit (który powinienem był usunąć), który nie miał RxJavaCallAdapterFactory. Rozdziera mi obecny kod i jest trochę bałaganu. Dziękuję za pomoc, tak czy inaczej. – Bryan

Odpowiedz

16

spróbować czegoś takiego:

import okhttp3.ResponseBody; 
import retrofit2.Response; 

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

Edit: Nie zapomnij trzeba określić adaptera do RxJava:

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

Próbowałem tego samego wyniku:/Próbowałem też zwykłego 'okhttp3.Respone', które też nie działa. – Bryan

+0

Tak, poprawnie skonfigurowałem 'RxJavaCallAdapterFactory', ponieważ moje inne odpowiedzi" Observable "działają zgodnie z oczekiwaniami. – Bryan

+2

Nie będzie działać z okhttp3.Respone, potrzebujesz odpowiedzi Retrofit. –