[英]Unable to create call adapter for class example.Simple
我正在使用帶有 SimpleXml 的改造 2.0.0-beta1。 我想要從 REST 服務中檢索簡單 (XML) 資源。 使用 SimpleXML 編組/解組 Simple 對象可以正常工作。
使用此代碼時(轉換為 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"));
服務:
public interface SimpleService {
@GET("/simple/{id}")
Simple getSimple(@Path("id") String id);
}
我得到這個例外:
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)
我錯過了什么? 我知道通過Call
包裝返回類型是可行的。 但我希望服務將業務對象作為類型返回(並在同步模式下工作)。
更新
按照不同答案的建議添加額外的依賴項和.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
后,我仍然收到此錯誤:
Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for class simple.Simple. Tried:
* retrofit.RxJavaCallAdapterFactory
* retrofit.DefaultCallAdapter$1
在Kotlin和協程的情況下,當我從CoroutineScope(Dispatchers.IO).launch{}
調用此函數時忘記將 api 服務函數標記為suspend
時,就會發生這種情況:
用法:
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>
}
簡短的回答:在您的服務界面中返回Call<Simple>
。
看起來 Retrofit 2.0 正在嘗試找到一種為您的服務接口創建代理對象的方法。 它希望你這樣寫:
public interface SimpleService {
@GET("/simple/{id}")
Call<Simple> getSimple(@Path("id") String id);
}
但是,當您不想返回Call
時,它仍然希望表現得很好並且靈活。 為了支持這一點,它具有CallAdapter
的概念,它應該知道如何將Call<Simple>
調整為Simple
。
僅當您嘗試返回rx.Observable<Simple>
時,使用RxJavaCallAdapterFactory
才有用。
最簡單的解決方案是按照 Retrofit 的預期返回一個Call
。 如果你真的需要,你也可以寫一個CallAdapter.Factory
。
添加依賴項:
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'
以這種方式創建您的適配器:
Retrofit rest = new Retrofit.Builder()
.baseUrl(endpoint)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
addCallAdapterFactory ()
和addConverterFactory ()
都需要調用。
服務:
public interface SimpleService {
@GET("/simple/{id}")
Call<Simple> getSimple(@Path("id") String id);
}
將Simple
修改為Call<Simple>
。
使用新的 Retrofit(2.+),您需要添加 addCallAdapterFactory,它可以是普通的,也可以是 RxJavaCallAdapterFactory(用於 Observables)。 我認為您也可以添加更多內容。 它會自動檢查要使用哪一個。 請參閱下面的工作示例。 您還可以查看此鏈接以獲取更多詳細信息。
Retrofit retrofit = new Retrofit.Builder().baseUrl(ApiConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build()
如果你想使用retrofit2
並且你不想總是返回 retrofit2.Call retrofit2.Call<T>
,你必須創建你自己的CallAdapter.Factory
,它返回你所期望的簡單類型。 簡單的代碼如下所示:
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
}
}
};
}
}
然后簡單地在 Retrofit 中注冊SynchronousCallAdapterFactory
應該可以解決您的問題。
Retrofit rest = new Retrofit.Builder()
.baseUrl(endpoint)
.addConverterFactory(SimpleXmlConverterFactory.create())
.addCallAdapterFactory(SynchronousCallAdapterFactory.create())
.build();
之后,您可以在沒有retrofit2.Call
的情況下返回簡單類型。
public interface SimpleService {
@GET("/simple/{id}")
Simple getSimple(@Path("id") String id);
}
為改造 2 添加以下依賴項
compile 'com.squareup.retrofit2:retrofit:2.1.0'
用於 GSON
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
對於可觀察的
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
對於 XML ,您必須包含以下依賴項
compile 'com.squareup.retrofit2:converter-simplexml:2.1.0'
更新服務調用如下
final Retrofit rest = new Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(SimpleXmlConverterFactory.create())
.baseUrl(endpoint)
.build();
SimpleService service = rest.create(SimpleService.class);
IllegalArgumentException:無法為類 java.lang.Object 創建調用適配器
簡短回答:我通過以下更改解決了它
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"
祝你好運
對於這種情況:
val apiService = RetrofitFactory.makeRetrofitService()
CoroutineScope(Dispatchers.IO).launch {
val response = apiService.myGetRequest()
// process response...
}
interface ApiService {
@GET("/my-get-request")
suspend fun myGetRequest(): Response<String>
}
suspend
函數中使用的所有方法都必須標記為suspend
,因為它是由 Corountine 管理的。 在這里查看更多信息。
因此,如果您在 CoroutineScope 或任何suspend
標記的方法中調用 API 服務函數時未將其標記為suspend
,則 android 應用程序會崩潰並Exception in thread "main" java.lang.IllegalArgumentException: Unable to create call adapter for class example.class
錯誤。
在我的情況下使用這個
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
有了這個
new Retrofit.Builder().addCallAdapterFactory(RxJava2CallAdapterFactory.create())...
當沒有其他工作時解決了問題
如果你沒有使用 RxJava,那么僅僅為了改造而添加 RxJava 是沒有意義的。 2.5.0
支持內置的CompletableFuture
,您可以在不添加任何其他庫或適配器的情況下使用它。
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>
}
用法:
Retrofit.Builder()
.addConverterFactory(SimpleXmlConverterFactory.create())
.baseUrl("https://api.example.com")
.build()
.create(Api::class.java)
我將 Coroutines 與CoroutineCallAdapterFactory一起使用,但不小心忘記了使函數suspend 。 希望它可以幫助某人!
只是為了讓遷移、不使用 Rx 或想要同步調用的人更清楚調用示例 - 調用本質上替換(包裝)響應,這意味着:
Response<MyObject> createRecord(...);
變成
Call<MyObject> createRecord(...);
並不是
Call<Response<MyObject>> createRecord(...);
(仍然需要適配器)
然后,調用將允許您仍然使用isSuccessful
,因為它實際上返回一個響應。 因此,您可以執行以下操作:
myApi.createRecord(...).execute().isSuccessful()
或訪問您的類型(MyObject),如:
MyObject myObj = myApi.createRecord(...).execute().body();
public interface SimpleService {
@GET("/simple/{id}")
Simple getSimple(@Path("id") String id);
}
與網絡的通信是通過單獨的線程完成的,所以你應該用它來改變你的 Simple 。
public interface SimpleService {
@GET("/simple/{id}")
Call<Simple> getSimple(@Path("id") String id);
}
在我的情況下,我使用
com.squareup.retrofit2:adapter-rxjava:2.5.0 //notice rxjava
代替
com.squareup.retrofit2:adapter-rxjava2:2.5.0 //notice rxjava2
使用 io.reactivex.rxjava2 時,您應該使用io.reactivex.rxjava2
com.squareup.retrofit2:adapter-rxjava2:2.5.0
您可以實現一個回調,從 onResponse 函數中獲取 Simple。
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
}
}
我找到了一個解決方案,在我的情況下,我使用來自 JAVA 的ApiInterface.java
來連接來自MyViewModel.kt
的 MyViewModel.kt。
這是ApiInterface.java
@GET(Constant.CONNECTION) 調用<com.example.kt.model.ConnectionResponse> ConnectionKt();
您需要創建一個新的 Kotlin 類,命名為ApiTemporary.kt
類 ApiTemporary(私有 val apiInterface:ApiInterface = RetrofitClient.getRetrofitInstance().create(ApiInterface::class.java)){
暫停樂趣 getConnectionKt(): Response { return apiInterface.ConnectionKt().awaitResponse() } }
所以最后,在MyViewModel.kt
,你可以這樣做
val data = withContext(ioDispatcher) { val result = apiTemporary.getConnectionKt() if (result.isSuccessful) { Resource.Success(result.body()) } else { Resource.Error("服務器錯誤。請重試") } } _connection.value = 數據
因此, ApiTemporary
將有助於將它們從 Java 轉換為 Kotlin,這是協程的使用
我通過在 gradle 中將改造版本更新到 2.9.0 來解決
如果您的 API 接口返回 Response 對象,那么您可能忘記在 API 接口中添加掛起功能。
API接口
interface WeatherAPI {
@GET("/data/2.5/weather")
suspend fun getWeatherInfo(
@Query("q") query: String
): Response<WeatherResponse>
}
存儲庫
class WeatherRepositoryImpl @Inject constructor(
private val weatherAPI: WeatherAPI
) : WeatherRepository {
override suspend fun getWeatherInfo(query: String): Resource<WeatherResponse> {
try {
val response = weatherAPI.getWeatherInfo(query)
if (response.isSuccessful) {
response.body()?.let {
return Resource.success(it)
} ?: return Resource.error("Unknown error occurred", null)
} else {
return Resource.error("Unknown error occured", null)
}
} catch (e: Exception) {
return Resource.error("Please check your internet connection", null)
}
}
}
我解決這個問題的方法是將這個添加到應用程序的 gradle 文件中,如果沒有設置配置會有沖突,也許這將在庫的穩定版本中修復:
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'
}
並以這種方式創建您的適配器:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(endPoint)
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
希望能幫助到你!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.