2017-02-05 61 views
6

Próbuję użyć rxJava, rxAndroid, Retrofit2 i OkHTTP3, aby pobrać plik z punktu końcowego adresu URL. Mój kod nie może utworzyć adaptera połączenia dla "Observable < retrofit2.Response < okhttp3.ResponseBody >>". Te metody są dla mnie nowością, więc uważam, że brakuje tu ważnej koncepcji. Każdy kierunek lub punkty są mile widziane.RxAndroid i Retrofit: Nie można utworzyć adaptera połączenia dla io.reactivex.Observable <retrofit2.Response <okhttp3.ResponseBody >>

krytyczny wyjątek: główny procesu: com.example.khe11e.rxdownloadfile PID: 14130 java.lang.IllegalArgumentException: Nie można tworzyć połączenia adapter do io.reactivex.Observable> dla metody RetrofitInterface.downloadFileByUrlRx w retrofit2.ServiceMethod $ Builder.methodError (ServiceMethod.java:720) w retrofit2.ServiceMethod $ Builder.createCallAdapter (ServiceMethod.java:234) w retrofit2.ServiceMethod $ Builder.build (ServiceMethod.java:160) w retrofit2 .Retrofit.loadServiceMethod (Retrofit.java:166) na retrofit2.Retrofit $ 1.invoke (Retrofit.java:145) na java.lang.reflect.Proxy.invoke (Proxy.java:393) na $ Proxy0.downloadFileByUrlRx (Unknown Source) na com.example.khe11e.rxdownloadfile.MainActivity.downloadImage (MainActivity.java:46) na com.example.khe11e.rxdownloadfile.MainActivity 1.onClick (MainActivity.java:39) na android.view.View.performClick (View.java:5207) na android.view.View $ PerformClick.run (View.java : 21168) na android.os.Handler.handleCallback (Handler.java:746) na android.os.Handler.dispatchMessage (Handler.java:95) na android.os.Looper.loop (Looper.java:148) na android.app.ActivityThread.main (ActivityThread.java:5491) w java.lang.reflect.Method.invoke (metoda macierzysta) na com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:728) na com.android.internal.os.ZygoteInit.main (ZygoteInit.java:618) Spowodowane przez: java.lang. IllegalArgumentException: Nie można znaleźć adaptera połączenia dla io.reactivex.Observable>. Próbowano: * retrofit2.adapter.rxjava.RxJavaCallAdapterFactory * retrofit2.ExecutorCallAdapterFactory w retrofit2.Retrofit.nextCallAdapter (Retrofit.java:237) w retrofit2.Retrofit.callAdapter (Retrofit.java:201) w retrofit2.ServiceMethod $ Builder.createCallAdapter (ServiceMethod.java:232) ... 16 więcej

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

Próbowałem dodanie połączeń jak wspomniano here tak to wygląda:

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

jednak powoduje to problemy z funkcją flatMap ponieważ nie można znaleźć symbol metoda flatMap (funkcja < Odpowiedź < ResponseBody>, Observable < Plik >>).

Odpowiedz

39

Używasz RxJava adapter do modernizacji, wymień go RxJava wariant:

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

UPDATE

Wychodząc z modernizacją wersji 2.2.0 jest wywołanie pierwszej partii adapter dla RxJava2:

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

uratowałeś mi boczek !! –

-3

Ponieważ używasz nagłówka odpowiedzi, więc zamień ResponseBody na Object wszędzie.

12

Dla nowych użytkowników (lipiec/2017):

Na pewno wprowadziłeś wersję swojej biblioteki.

I zostały z wykorzystaniem najnowszej wersji 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) Upewnij się, że masz taką samą Retrofit Retrofit-RxJava i adaptery.

2) Wykorzystanie skompilować

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

nie

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

i używać RxJava2CallAdapterFactory.create() zamiast RxJavaCallAdapterFactory.create() budując modernizacji.

Update: Listopad/2017

wersja Rxjava zostanie zaktualizowany do 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

i użyj 'RxJava2CallAdapterFactory.create()' zamiast 'RxJavaCallAdapterFactory.create()' podczas budowania retrofitu. –

+1

Dziękuję za uwagę. zaktualizowałem odpowiedź za pomocą tego. –

+1

I użyj także ** io.reactivex.schedulers.Schedulers ** zamiast ** rx.schedulers.Schedulers ** –