Saya menggunakan retrofit 2.0.0-beta1 dengan SimpleXml. Saya ingin mengambil sumber daya Simple (XML) dari layanan REST. Marshalling / Unmarshalling objek Simple dengan SimpleXML berfungsi dengan baik.
Saat menggunakan kode ini (bentuk yang diubah sebelum kode 2.0.0):
final Retrofit rest = new Retrofit.Builder()
.addConverterFactory(SimpleXmlConverterFactory.create())
.baseUrl(endpoint)
.build();
SimpleService service = rest.create(SimpleService.class);
LOG.info(service.getSimple("572642"));
Layanan:
public interface SimpleService {
@GET("/simple/{id}")
Simple getSimple(@Path("id") String id);
}
Saya mendapatkan pengecualian ini:
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)
Apa yang saya lewatkan? Saya tahu bahwa membungkus tipe pengembalian dengan sebuah Call
karya. Tapi saya ingin layanan mengembalikan objek bisnis sebagai tipe (dan bekerja dalam mode sinkronisasi).
MEMPERBARUI
Setelah menambahkan ketergantungan tambahan dan .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
seperti yang disarankan oleh jawaban yang berbeda, saya masih mendapatkan kesalahan ini:
Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for class simple.Simple. Tried:
* retrofit.RxJavaCallAdapterFactory
* retrofit.DefaultCallAdapter$1
java
rest
retrofit
simple-framework
rmuller
sumber
sumber
Jawaban:
Jawaban singkat: kembali
Call<Simple>
ke antarmuka layanan Anda.Sepertinya Retrofit 2.0 mencoba menemukan cara untuk membuat objek proxy untuk antarmuka layanan Anda. Ini mengharapkan Anda untuk menulis ini:
public interface SimpleService { @GET("/simple/{id}") Call<Simple> getSimple(@Path("id") String id); }
Namun, tetap ingin bermain bagus dan fleksibel ketika Anda tidak ingin mengembalikan
Call
. Untuk mendukung hal tersebut, maka memiliki konsep aCallAdapter
, yaitu mengetahui bagaimana mengadaptasi aCall<Simple>
menjadi aSimple
.Penggunaan
RxJavaCallAdapterFactory
hanya berguna jika Anda mencoba mengembalikanrx.Observable<Simple>
.Solusi paling sederhana adalah mengembalikan
Call
seperti yang diharapkan Retrofit. Anda juga dapat menulisCallAdapter.Factory
jika Anda benar-benar membutuhkannya.sumber
Call<Simple>
cara kerjanya. Namun, seperti yang dinyatakan dalam pertanyaan saya, preferensi saya adalah kembaliSimple
(seperti yang terjadi di versi sebelumnya). Kesimpulan saya adalah : tidak mungkin tanpa kode tambahan.Call<Simple>
rusak. Paket apa yangSimple
termasuk?Simple
adalah kelas yang disebutkan dalam pertanyaan OP. Tautannya adalah keCall<T>
.Dalam kasus Kotlin dan coroutine , situasi ini terjadi ketika saya lupa menandai fungsi layanan api seperti
suspend
ketika saya memanggil fungsi ini dariCoroutineScope(Dispatchers.IO).launch{}
:Pemakaian:
val apiService = RetrofitFactory.makeRetrofitService() CoroutineScope(Dispatchers.IO).launch { val response = apiService.myGetRequest() // process response... }
ApiService.kt
interface ApiService { @GET("/my-get-request") suspend fun myGetRequest(): Response<String> }
sumber
tambahkan dependensi:
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'
buat adaptor Anda dengan cara ini:
Retrofit rest = new Retrofit.Builder() .baseUrl(endpoint) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(SimpleXmlConverterFactory.create()) .build();
addCallAdapterFactory ()
danaddConverterFactory ()
keduanya perlu dipanggil.Layanan:
public interface SimpleService { @GET("/simple/{id}") Call<Simple> getSimple(@Path("id") String id); }
Ubah
Simple
menjadiCall<Simple>
.sumber
Call
ke antarmuka layananCompletableFuture
Lihat stackoverflow.com/questions/32269064/…Dengan Retrofit baru (2. +) Anda perlu menambahkan addCallAdapterFactory yang bisa jadi yang normal atau RxJavaCallAdapterFactory (untuk Observables). Saya pikir Anda juga dapat menambahkan lebih dari keduanya. Secara otomatis memeriksa mana yang akan digunakan. Lihat contoh kerja di bawah ini. Anda juga dapat memeriksa tautan ini untuk lebih jelasnya.
Retrofit retrofit = new Retrofit.Builder().baseUrl(ApiConfig.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build()
sumber
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
com.squareup.retrofit2:adapter-rxjava:2.1.0
dancom.squareup.retrofit2:converter-gson:2.1.0
Jika Anda ingin menggunakan
retrofit2
dan Anda tidak ingin selalu kembaliretrofit2.Call<T>
, Anda harus membuatnya sendiriCallAdapter.Factory
yang mengembalikan tipe sederhana seperti yang Anda harapkan. Kode sederhananya dapat terlihat seperti ini: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 } } }; } }
Kemudian daftar sederhana
SynchronousCallAdapterFactory
di Retrofit akan menyelesaikan masalah Anda.Retrofit rest = new Retrofit.Builder() .baseUrl(endpoint) .addConverterFactory(SimpleXmlConverterFactory.create()) .addCallAdapterFactory(SynchronousCallAdapterFactory.create()) .build();
Setelah itu Anda bisa mengembalikan tipe sederhana tanpa
retrofit2.Call
.public interface SimpleService { @GET("/simple/{id}") Simple getSimple(@Path("id") String id); }
sumber
2.0.0-beta3
itu adalah antarmuka, sekarang dalam versi2.1.0
itu adalah kelas. Saya mengedit kode saya, agar lebih aktual. Terima kasih.Simple getSimple()
danResponse<Simple> getSimple()
permintaan ini: github.com/jaredsburrows/retrofit2-synchronous-adapter .Tambahkan dependensi berikut untuk retrofit 2
compile 'com.squareup.retrofit2:retrofit:2.1.0'
untuk GSON
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
untuk observasi
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
Dalam kasus Anda untuk XML, Anda harus menyertakan dependensi berikut
compile 'com.squareup.retrofit2:converter-simplexml:2.1.0'
Perbarui panggilan layanan seperti di bawah ini
final Retrofit rest = new Retrofit.Builder() .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(SimpleXmlConverterFactory.create()) .baseUrl(endpoint) .build(); SimpleService service = rest.create(SimpleService.class);
sumber
IllegalArgumentException: Tidak dapat membuat adaptor panggilan untuk kelas java.lang.Object
Jawaban singkat: Saya telah menyelesaikannya dengan perubahan berikut
ext.retrofit2Version = '2.4.0' -> '2.6.0' implementation"com.squareup.retrofit2:retrofit:$retrofit2Version" implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit2Version" implementation "com.squareup.retrofit2:converter-gson:$retrofit2Version"
Semoga berhasil
sumber
dalam kasus saya menggunakan ini
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
dengan ini
new Retrofit.Builder().addCallAdapterFactory(RxJava2CallAdapterFactory.create())...
memecahkan masalah ketika tidak ada yang berhasil
sumber
Jika Anda tidak menggunakan RxJava dengan benar, tidak masuk akal untuk menambahkan RxJava hanya untuk retrofit.
2.5.0
memiliki dukungan untukCompletableFuture
bawaan yang dapat Anda gunakan tanpa menambahkan pustaka atau adaptor lain.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> }
Pemakaian:
Retrofit.Builder() .addConverterFactory(SimpleXmlConverterFactory.create()) .baseUrl("https://api.example.com") .build() .create(Api::class.java)
sumber
Hanya untuk membuat contoh Panggilan lebih jelas bagi orang-orang yang bermigrasi, tidak menggunakan Rx, atau yang menginginkan panggilan sinkron - Panggilan pada dasarnya menggantikan (membungkus) Respons, artinya:
Response<MyObject> createRecord(...);
menjadi
Call<MyObject> createRecord(...);
dan tidak
(yang masih membutuhkan adaptor)
Panggilan tersebut kemudian akan memungkinkan Anda untuk tetap menggunakan
isSuccessful
karena panggilan itu benar-benar mengembalikan Respons. Jadi Anda bisa melakukan sesuatu seperti:Atau akses Jenis Anda (MyObject) seperti:
sumber
public interface SimpleService { @GET("/simple/{id}") Simple getSimple(@Path("id") String id); }
Komunikasi dengan jaringan dilakukan dengan utas terpisah sehingga Anda harus mengubah Sederhana Anda dengan itu.
public interface SimpleService { @GET("/simple/{id}") Call<Simple> getSimple(@Path("id") String id); }
sumber
Dalam kasus saya, saya menggunakan
com.squareup.retrofit2:adapter-rxjava:2.5.0 //notice rxjava
dari pada
com.squareup.retrofit2:adapter-rxjava2:2.5.0 //notice rxjava2
Anda harus menggunakan
com.squareup.retrofit2:adapter-rxjava2:2.5.0
saat menggunakanio.reactivex.rxjava2
sumber
Anda dapat mengimplementasikan Callback, mendapatkan fungsi Simple dari onResponse.
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 } }
sumber
Cara saya memperbaiki masalah ini adalah menambahkan ini ke file gradle aplikasi, jika konfigurasi tidak diatur akan ada konflik, mungkin ini akan diperbaiki dalam rilis pustaka yang stabil:
configurations { compile.exclude group: 'stax' compile.exclude group: 'xpp3' } dependencies { compile 'com.squareup.retrofit:retrofit:2.0.0-beta1' compile 'com.squareup.retrofit:converter-simplexml:2.0.0-beta1' }
dan buat adaptor Anda dengan cara ini:
Retrofit retrofit = new Retrofit.Builder() .baseUrl(endPoint) .addConverterFactory(SimpleXmlConverterFactory.create()) .build();
Semoga membantu!
sumber