RxAndroid and Retrofit: Unable to create call adapter for io.reactivex.Observable<retrofit2.Response<okhttp3.ResponseBody>>

匿名 (未验证) 提交于 2019-12-03 02:15:02

问题:

I am trying use rxJava, rxAndroid, Retrofit2, and OkHTTP3 to download a file from a URL endpoint. My code is unable to create the call adapter for an "Observable< retrofit2.Response< okhttp3.ResponseBody>>". These methods are new to me so I believe I'm missing an important concept here. Any direction or points is greatly appreciated.

FATAL EXCEPTION: main Process: com.example.khe11e.rxdownloadfile, PID: 14130 java.lang.IllegalArgumentException: Unable to create call adapter for io.reactivex.Observable> for method RetrofitInterface.downloadFileByUrlRx at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:720) at retrofit2.ServiceMethod$Builder.createCallAdapter(ServiceMethod.java:234) at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:160) at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:166) at retrofit2.Retrofit$1.invoke(Retrofit.java:145) at java.lang.reflect.Proxy.invoke(Proxy.java:393) at $Proxy0.downloadFileByUrlRx(Unknown Source) at com.example.khe11e.rxdownloadfile.MainActivity.downloadImage(MainActivity.java:46) at com.example.khe11e.rxdownloadfile.MainActivity$1.onClick(MainActivity.java:39) at android.view.View.performClick(View.java:5207) at android.view.View$PerformClick.run(View.java:21168) at android.os.Handler.handleCallback(Handler.java:746) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5491) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for io.reactivex.Observable>. Tried: * retrofit2.adapter.rxjava.RxJavaCallAdapterFactory * retrofit2.ExecutorCallAdapterFactory at retrofit2.Retrofit.nextCallAdapter(Retrofit.java:237) at retrofit2.Retrofit.callAdapter(Retrofit.java:201) at retrofit2.ServiceMethod$Builder.createCallAdapter(ServiceMethod.java:232) ... 16 more

build.gradle:

compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'io.reactivex.rxjava2:rxjava:2.0.4' compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' 

RetrofitInterface.java:

package com.example.khe11e.rxdownloadfile; import io.reactivex.Observable; import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.Response; import retrofit2.http.GET; import retrofit2.http.Streaming; import retrofit2.http.Url;  public interface RetrofitInterface {     // Retrofit 2 GET request for rxjava     @Streaming     @GET     Observable<Response<ResponseBody>> downloadFileByUrlRx(@Url String fileUrl); } 

MainActivity.java:

package com.example.khe11e.rxdownloadfile;  import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import java.io.File; import io.reactivex.Observable; import io.reactivex.ObservableEmitter; import io.reactivex.ObservableOnSubscribe; import io.reactivex.Observer; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.functions.Function; import io.reactivex.schedulers.Schedulers; import okhttp3.OkHttpClient; import okhttp3.ResponseBody; import okio.BufferedSink; import okio.Okio; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;  public class MainActivity extends AppCompatActivity {  Button downloadImgBtn;  @Override protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.activity_main);     downloadImgBtn = (Button) findViewById(R.id.downloadImgBtn);     downloadImgBtn.setOnClickListener(new View.OnClickListener() {         @Override         public void onClick(View v) {             downloadImage();         }     }); }  public void downloadImage(){     RetrofitInterface downloadService = createService(RetrofitInterface.class, "https://www.nasa.gov/");     downloadService.downloadFileByUrlRx("sites/default/files/iss_1.jpg")             .flatMap(processResponse())             .subscribeOn(Schedulers.io())             .observeOn(AndroidSchedulers.mainThread())             .subscribe(handleResult()); }  public <T> T createService(Class<T> serviceClass, String baseUrl){     Retrofit retrofit = new Retrofit.Builder()             .baseUrl(baseUrl)             .client(new OkHttpClient.Builder().build())             .addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build();     return retrofit.create(serviceClass); }  public Function<Response<ResponseBody>, Observable<File>> processResponse(){     return new Function<Response<ResponseBody>, Observable<File>>() {         @Override         public Observable<File> apply(Response<ResponseBody> responseBodyResponse) throws Exception {             return saveToDiskRx(responseBodyResponse);         }     }; }  private Observable<File> saveToDiskRx(final Response<ResponseBody> response){     return Observable.create(new ObservableOnSubscribe<File>() {         @Override         public void subscribe(ObservableEmitter<File> subscriber) throws Exception {             String header = response.headers().get("Content-Disposition");             String filename = header.replace("attachment; filename=", "");             new File("/data/data/" + getPackageName() + "/images").mkdir();             File destinationFile = new File("/data/data/" + getPackageName() + "/images/" + filename);              BufferedSink bufferedSink = Okio.buffer(Okio.sink(destinationFile));             bufferedSink.writeAll(response.body().source());             bufferedSink.close();              subscriber.onNext(destinationFile);             subscriber.onComplete();         }     }); }  private Observer<File> handleResult(){     return new Observer<File>() {         @Override         public void onSubscribe(Disposable d) {             Log.d("OnSubscribe", "OnSubscribe");         }          @Override         public void onNext(File file) {             Log.d("OnNext", "File downloaded to " + file.getAbsolutePath());         }          @Override         public void onError(Throwable e) {             e.printStackTrace();             Log.d("Error", "Error " + e.getMessage());         }          @Override         public void onComplete() {             Log.d("OnComplete", "onCompleted");         }     }; } } 

I've tried adding Call as mentioned here so it looks like:

Call<Observable<Response<ResponseBody>>> downloadFileByUrlRx(@Url String fileUrl); 

however this causes issues with the flatMap function as it cannot find symbol method flatMap(Function< Response< ResponseBody>,Observable< File>>).

回答1:

You are using RxJava1 adapter for Retrofit, replace it with RxJava2 variant:

//compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' 

UPDATE

Starting with Retrofit version 2.2.0 there is a first-party call adapter for RxJava2:

compile 'com.squareup.retrofit2:retrofit:2.2.0' compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0' 


回答2:

For new comers (July/2017) :

You messed your library version for sure.

I have been using latest version of RXAndroid 2.0.1

compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'io.reactivex.rxjava2:rxjava:2.1.0' compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' 

1) Make sure you have same Retrofit and Retrofit-RxJava Adapters.

2) Use compile

compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'  

not

compile 'com.squareup.retrofit2:adapter-rxjava:2.3.0' 

and use RxJava2CallAdapterFactory.create() instead of RxJavaCallAdapterFactory.create() while building retrofit.

Update : November/2017

Rxjava version is updated to 2.1.5

compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'io.reactivex.rxjava2:rxjava:2.1.5' compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' 


回答3:

Since you use response header, so replace ResponseBody to Object everywhere.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!