Ich benutze Retrofit 2.0.0-beta1 mit SimpleXml. Ich möchte, dass die Simple-Ressource (XML) von einem REST -Dienst abgerufen wird.
Bei Verwendung dieses Codes (konvertiertes Formular vor 2.0.0 Code):
final Retrofit rest = new Retrofit.Builder()
.addConverterFactory(SimpleXmlConverterFactory.create())
.baseUrl(endpoint)
.build();
SimpleService service = rest.create(SimpleService.class);
LOG.info(service.getSimple("572642"));
Bedienung:
public interface SimpleService {
@GET("/simple/{id}")
Simple getSimple(@Path("id") String id);
}
Ich bekomme diese Ausnahme:
Exception in thread "main" Java.lang.IllegalArgumentException: Unable to create call adapter for class example.Simple
for method SimpleService.getSimple
at retrofit.Utils.methodError(Utils.Java:201)
at retrofit.MethodHandler.createCallAdapter(MethodHandler.Java:51)
at retrofit.MethodHandler.create(MethodHandler.Java:30)
at retrofit.Retrofit.loadMethodHandler(Retrofit.Java:138)
at retrofit.Retrofit$1.invoke(Retrofit.Java:127)
at com.Sun.proxy.$Proxy0.getSimple(Unknown Source)
Was vermisse ich? Ich weiß, dass das Umhüllen des Rückgabetyps durch eine Call
funktioniert. Ich möchte jedoch, dass der Service Geschäftsobjekte als Typ zurückgibt (und im Synchronisationsmodus arbeitet).
UPDATE
Nachdem ich die zusätzlichen Abhängigkeiten und .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
hinzugefügt habe, wie in verschiedenen Antworten vorgeschlagen, erhalte ich immer noch diesen Fehler:
Caused by: Java.lang.IllegalArgumentException: Could not locate call adapter for class simple.Simple. Tried:
* retrofit.RxJavaCallAdapterFactory
* retrofit.DefaultCallAdapter$1
Kurze Antwort: Geben Sie Call<Simple>
in Ihre Service-Schnittstelle ein.
Offenbar versucht Retrofit 2.0, ein Proxy-Objekt für Ihre Service-Schnittstelle zu erstellen. Es erwartet, dass Sie dies schreiben:
public interface SimpleService {
@GET("/simple/{id}")
Call<Simple> getSimple(@Path("id") String id);
}
Es möchte jedoch immer noch Nizza spielen und flexibel sein, wenn Sie keine Call
zurückgeben möchten. Um dies zu unterstützen, hat es das Konzept einer CallAdapter
, das wissen soll, wie ein Call<Simple>
in eine Simple
angepasst wird.
Die Verwendung von RxJavaCallAdapterFactory
ist nur nützlich, wenn Sie versuchen, rx.Observable<Simple>
zurückzugeben.
Die einfachste Lösung ist die Rückgabe einer Call
, wie Retrofit erwartet. Sie könnten auch einen CallAdapter.Factory
schreiben, wenn Sie es wirklich brauchen.
abhängigkeiten hinzufügen:
compile 'com.squareup.retrofit:retrofit:2.0.0-beta1'
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta1'
erstellen Sie Ihren Adapter auf diese Weise:
Retrofit rest = new Retrofit.Builder()
.baseUrl(endpoint)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
addCallAdapterFactory ()
und addConverterFactory ()
müssen beide aufgerufen werden.
Bedienung:
public interface SimpleService {
@GET("/simple/{id}")
Call<Simple> getSimple(@Path("id") String id);
}
Ändern Sie Simple
in Call<Simple>
.
Mit dem neuen Retrofit (2. +) müssen Sie addCallAdapterFactory hinzufügen. Dies kann eine normale oder eine RxJavaCallAdapterFactory (für Observables) sein. Ich denke, Sie können auch mehr als beides hinzufügen. Es prüft automatisch, welches verwendet werden soll. Siehe unten ein Arbeitsbeispiel. Sie können auch diesen Link für weitere Details überprüfen.
Retrofit retrofit = new Retrofit.Builder().baseUrl(ApiConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build()
Fügen Sie die folgenden Abhängigkeiten für die Nachrüstung hinzu 2
compile 'com.squareup.retrofit2:retrofit:2.1.0'
für GSON
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
für Observables
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
In Ihrem Fall für XML müssen Sie die folgenden Abhängigkeiten hinzufügen
compile 'com.squareup.retrofit2:converter-simplexml:2.1.0'
Aktualisieren Sie den Serviceabruf wie folgt
final Retrofit rest = new Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(SimpleXmlConverterFactory.create())
.baseUrl(endpoint)
.build();
SimpleService service = rest.create(SimpleService.class);
Wenn Sie retrofit2
verwenden möchten und nicht immer retrofit2.Call<T>
zurückgeben möchten, müssen Sie einen eigenen CallAdapter.Factory
erstellen, der den einfachen Typ zurückgibt, wie Sie es erwartet haben. Der einfache Code kann folgendermaßen aussehen:
import retrofit2.Call;
import retrofit2.CallAdapter;
import retrofit2.Retrofit;
import Java.lang.annotation.Annotation;
import Java.lang.reflect.Type;
public class SynchronousCallAdapterFactory extends CallAdapter.Factory {
public static CallAdapter.Factory create() {
return new SynchronousCallAdapterFactory();
}
@Override
public CallAdapter<Object, Object> get(final Type returnType, Annotation[] annotations, Retrofit retrofit) {
// if returnType is retrofit2.Call, do nothing
if (returnType.toString().contains("retrofit2.Call")) {
return null;
}
return new CallAdapter<Object, Object>() {
@Override
public Type responseType() {
return returnType;
}
@Override
public Object adapt(Call<Object> call) {
try {
return call.execute().body();
} catch (Exception e) {
throw new RuntimeException(e); // do something better
}
}
};
}
}
Dann sollten Sie einfach die SynchronousCallAdapterFactory
in Retrofit registrieren, um Ihr Problem zu lösen.
Retrofit rest = new Retrofit.Builder()
.baseUrl(endpoint)
.addConverterFactory(SimpleXmlConverterFactory.create())
.addCallAdapterFactory(SynchronousCallAdapterFactory.create())
.build();
Danach können Sie einfachen Typ ohne retrofit2.Call
zurückgeben.
public interface SimpleService {
@GET("/simple/{id}")
Simple getSimple(@Path("id") String id);
}
in meinem Fall mit diesem
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
mit diesem
new Retrofit.Builder().addCallAdapterFactory(RxJava2CallAdapterFactory.create())...
gelöst das problem wenn nichts anderes funktionierte
Nur um die Anrufbeispiele für Personen zu verdeutlichen, die migrieren, keinen Empfängerempfänger verwenden oder synchrone Anrufe wünschen - Anruf ersetzt im Wesentlichen (wraps) Response, dh:
Response<MyObject> createRecord(...);
wird
Call<MyObject> createRecord(...);
und nicht
Call<Response<MyObject>> createRecord(...);
(was noch einen Adapter erfordert)
Mit dem Aufruf können Sie isSuccessful
weiterhin verwenden, da er tatsächlich eine Antwort zurückgibt. So kannst du so etwas tun:
myApi.createRecord(...).execute().isSuccessful()
Oder greifen Sie auf Ihren Typ (MyObject) wie folgt zu:
MyObject myObj = myApi.createRecord(...).execute().body();
Wenn Sie RxJava nicht verwenden, ist es nicht sinnvoll, RxJava nur zum Nachrüsten hinzuzufügen. 2.5.0
unterstützt CompletableFuture
, die Sie verwenden können, ohne eine andere Bibliothek oder einen anderen Adapter hinzuzufügen.
build.gradle.kts
implementation("com.squareup.retrofit2:retrofit:2.5.0")
implementation("com.squareup.retrofit2:retrofit-converters:2.5.0")
Api.kt
interface Api {
@GET("/resource")
fun listCompanies(): CompletableFuture<ResourceDto>
}
Verwendungszweck:
Retrofit.Builder()
.addConverterFactory(SimpleXmlConverterFactory.create())
.baseUrl("https://api.example.com")
.build()
.create(Api::class.Java)
In meinem Fall habe ich verwendet
com.squareup.retrofit2:adapter-rxjava:2.5.0 //notice rxjava
anstatt
com.squareup.retrofit2:adapter-rxjava2:2.5.0 //notice rxjava2
sie sollten com.squareup.retrofit2:adapter-rxjava2:2.5.0
verwenden, wenn Sie io.reactivex.rxjava2
verwenden.
Sie können einen Rückruf implementieren und die Funktion Simple from onResponse verwenden.
public class MainActivity extends Activity implements Callback<Simple> {
protected void onCreate(Bundle savedInstanceState) {
final Retrofit rest = new Retrofit.Builder()
.addConverterFactory(SimpleXmlConverterFactory.create())
.baseUrl(endpoint)
.build();
SimpleService service = rest.create(SimpleService.class);
Call<Simple> call = service.getSimple("572642");
//asynchronous call
call.enqueue(this);
return true;
}
@Override
public void onResponse(Response<Simple> response, Retrofit retrofit) {
// response.body() has the return object(s)
}
@Override
public void onFailure(Throwable t) {
// do something
}
}
public interface SimpleService {
@GET("/simple/{id}")
Simple getSimple(@Path("id") String id);
}
Die Kommunikation mit dem Netzwerk erfolgt über einen separaten Thread, daher sollten Sie Ihr Simple damit ändern.
public interface SimpleService {
@GET("/simple/{id}")
Call<Simple> getSimple(@Path("id") String id);
}