无法为类example.Simple创建调用适配器。

190

我正在使用Retrofit 2.0.0-beta1与SimpleXml。我想从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

相关:https://dev59.com/6lwY5IYBdhLWcg3wcXaE - Hosam Aly
4
如需使用协程,请参考@chatlanin的答案。 - N J
19个回答

486

在使用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>
}

26
你救了我,兄弟。 - Guilherme Ramos
1
在使用协程时,您必须在函数中使用“suspend”。感谢您的帮助,伙计。 - Abubakar Rafi
2
节省了我的时间,谢谢 :) - Barrufet
1
我很烦恼,因为我看到的都是与RxJava相关的答案,但是OP的实际代码示例甚至没有使用RxJava。这就是我要找的答案! - Bitwise DEVS
2
在我的情况下,这个错误是因为我忘记在服务标记函数中使用suspend。谢谢回答。 :) - Miramax Mars
显示剩余7条评论

90

简短回答:在你的服务接口中返回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


1
是的,这确实是正确的答案 :(. 从一开始我就知道 Call<Simple> 是它的工作方式。然而,正如我在问题中所述,我的偏好是只返回 Simple(就像早期版本一样)。我的结论是:没有额外的代码是不可能的。 - rmuller
您提供的 Call<Simple> 链接已经失效了。Simple 属于哪个包? - shyam
感谢@shyam的提醒。我已经更新了链接。Simple是OP问题中提到的类。链接指向Call<T> - Hosam Aly

57

添加依赖项:

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>


7
我知道将Simple更改为Call<Simple>可以解决问题。然而,我不想在服务接口中引入Call类型。 - rmuller
你也可以使用 CompletableFuture,参考:https://dev59.com/0FwY5IYBdhLWcg3wup5c#55652910 - Johannes Barop

45

我曾使用带有CoroutineCallAdapterFactory的协程,但不小心忘记将函数标记为suspend。 希望对某些人有所帮助!


1
我也一样)很棒的发现! - undefined

39

使用新版Retrofit(2.+),您需要添加addCallAdapterFactory,它可以是普通的,也可以是RxJavaCallAdapterFactory(用于Observables)。我认为您还可以添加更多。它会自动检查要使用哪个。请参见下面的工作示例。您也可以查看此链接以获取更多详情。

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

1
好的链接!稍后会查看。 - rmuller
1
文档中仍然存在RestAdapter,并且没有展示如何使用Retrofit 2.0进行最简单的请求的示例。我遇到了“无法解析RxJavaCallAdapterFactory”的错误。花费了几个小时来进行最简单的Android HTTP请求。看起来这并不像他们所宣传的那么简单。也许他们应该多写一些文档。 - Vlado Pandžić
如果你正在使用Retrofit 2.0,那么请使用Retrofit而不是RestAdapter。 - Himanshu Virmani
5
RxJavaCallAdapterFactory需要与同一代码库中的adapter-rxjava工件配合使用。compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1' - Damien Diehl
3
对于 Retrofit2,请确保使用正确的依赖项com.squareup.retrofit2:adapter-rxjava:2.1.0com.squareup.retrofit2:converter-gson:2.1.0 - George Papas
显示剩余7条评论

19

如果您想使用retrofit2,并且不想总是返回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);
}

太棒了,谢谢。您知道是否有一种方法可以创建异步调用适配器吗?这样我就可以像这样调用服务:service.getSimple(“id”,new Adapter(){onFail(){} onSuccess(){} },而不是使用enqueue()和回调函数。 - markov00
@MateuszKorwel 总是会抛出一个新的 RuntimeException(e)!我想要返回一个字符串而不是 Simple。 - Dr.jacky
@Mr.Hyde 这应该可以工作。也许你的 REST 服务不起作用了?当你调用 call.execute().body() 时,你得到了什么异常? - Mateusz Korwel
3
谢谢您发布这个。我已经创建了一个库,围绕处理Simple getSimple()Response<Simple> getSimple()请求:https://github.com/jaredsburrows/retrofit2-synchronous-adapter。 - Jared Burrows
这个答案中的代码在响应错误时不会抛出 HttpException。我转而使用了 @JaredBurrows 的解决方案。 - Richard Collette
显示剩余2条评论

13

对于这个案例:

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,因为这样才能通过协程进行管理。更多信息请查看此处。 所以,如果您在 CoroutineScope 或任何已标记为 suspend 的方法内调用 API 服务函数而未将其标记为 suspend,则 Android 应用程序将崩溃并抛出“Exception in thread "main" java.lang.IllegalArgumentException: Unable to create call adapter for class example.class”错误。

13

为使用Retrofit 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);

这和我的设置一样。 - rmuller
1
创建适配器时,请确保添加以下行:.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) - Shayan_Aryan
无法解析:com.squareup.retrofit:adapter-rxjava:2.1.0 - ozmank
1
@ozmank,这是retrofit2,我也已经更新了我的答案。请试一下。 - rahul.ramanujam

12

参数异常:无法为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"

祝你好运


4
在我的情况下,使用这个。
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'

使用这个

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

当其他方法都无效时,解决了问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接