无法为 class example.Simple 创建呼叫适配器

Unable to create call adapter for class example.Simple

我正在使用带有 SimpleXml 的改造 2.0.0-beta1。我想从 REST 服务中检索一个简单 (XML) 资源。 Marshalling/Unmarshalling 带有 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.invoke(Retrofit.java:127)
    at com.sun.proxy.$Proxy0.getSimple(Unknown Source)

我错过了什么?我知道用 Call 包装 return 类型是可行的。但我希望服务以 return 业务对象为类型(并在同步模式下工作)。

更新

按照不同答案的建议添加了额外的依赖项和 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 后,我仍然收到此错误:

Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for class simple.Simple. Tried:
 * retrofit.RxJavaCallAdapterFactory
 * retrofit.DefaultCallAdapter

对于新的 Retrofit(2.+),您需要添加 addCallAdapterFactory,它可以是普通的或 RxJavaCallAdapterFactory(用于 Observables)。我认为你也可以添加更多。它会自动检查使用哪一个。请参阅下面的工作示例。您还可以查看 this link 了解更多详情。

 Retrofit retrofit = new Retrofit.Builder().baseUrl(ApiConfig.BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build()

为改造 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);

我解决这个问题的方法是将它添加到应用程序 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();

希望对您有所帮助!

添加依赖项:

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

}

修改SimpleCall<Simple>.

简答:return Call<Simple> 在您的服务界面中。

看起来 Retrofit 2.0 正在尝试找到一种为您的服务接口创建代理对象的方法。它希望你这样写:

public interface SimpleService {
    @GET("/simple/{id}")
    Call<Simple> getSimple(@Path("id") String id);
}

然而,当你不想 return Call 时,它仍然想表现得很好并且灵活。为了支持这一点,它有一个 CallAdapter 的概念,它应该知道如何将 Call<Simple> 改编成 Simple

RxJavaCallAdapterFactory 的使用仅在您尝试 return rx.Observable<Simple>.

时有用

最简单的解决方案是 return a Call 正如 Retrofit 所期望的那样。如果你真的需要它,你也可以写一个CallAdapter.Factory

你可以实现一个Callback,从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
    }

}

如果你想使用 retrofit2 而你不想总是 return retrofit2.Call<T>,你必须创建自己的 CallAdapter.Factory,return 简单按预期输入。简单的代码可以是这样的:

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();

之后你可以 return 没有 retrofit2.Call 的简单类型。

public interface SimpleService {
    @GET("/simple/{id}")
    Simple getSimple(@Path("id") String id);
}

在我的例子中使用这个

compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'

有了这个

new Retrofit.Builder().addCallAdapterFactory(RxJava2CallAdapterFactory.create())...

在其他方法都不起作用的情况下解决了问题

只是为了让正在迁移、不使用 Rx 或想要同步调用的人更清楚 Call 示例 - Call 本质上取代(包装)Response,意思是:

Response<MyObject> createRecord(...);

变成

Call<MyObject> createRecord(...);

而不是

Call<Response<MyObject>> createRecord(...);

(仍然需要适配器)


呼叫将允许您仍然使用 isSuccessful 因为它实际上是 returns 一个响应。所以你可以这样做:

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

时使用 com.squareup.retrofit2:adapter-rxjava2:2.5.0

如果您不使用 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)

IllegalArgumentException:无法为 class 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"

祝你好运

Kotlincoroutines 的情况下,当我忘记将 api 服务函数标记为 [=12 时,就会发生这种情况=] 当我从 CoroutineScope(Dispatchers.IO).launch{}:

调用这个函数时

用法:

    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>
}

我找到了解决方案,在我的情况下,我正在使用 JAVA 中的 ApiInterface.java 连接来自 KOTLIN 的 MyViewModel.kt

  1. 这是ApiInterface.java

    @GET(Constant.CONNECTION) 调用ConnectionKt();

  2. 您需要创建一个新的 Kotlin class,命名为 ApiTemporary.kt

    class ApiTemporary( 私有 val apiInterface: ApiInterface = RetrofitClient.getRetrofitInstance().create(ApiInterface::class.java) ) {

    暂停乐趣 getConnectionKt(): 响应 { return apiInterface.ConnectionKt().awaitResponse() } }

  3. 最后,在 MyViewModel.kt,你可以这样做

val data = withContext(ioDispatcher) { val 结果 = apiTemporary.getConnectionKt() 如果(result.isSuccessful){ Resource.Success(result.body()) } 别的 { 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)
        }
    }

}

对于这种情况:

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 管理。查看更多信息 here.

因此,如果在 CoroutineScope 或任何 suspend 标记的方法中调用它时,如果您没有将 API 服务函数标记为 suspend,android 应用程序会崩溃并抛出Exception in thread "main" java.lang.IllegalArgumentException: Unable to create call adapter for class example.class 错误。