无法为类示例创建呼叫适配器。简单


87

我正在使用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


对于使用协程的人,请检查@chatlanin答案
NJ

Answers:


66

简短答案:返回Call<Simple>您的服务界面。

看起来Retrofit 2.0正在尝试寻找一种为服务接口创建代理对象的方法。它希望您编写以下代码:

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

但是,当您不想返回时,它仍然希望表现出色并且保持灵活性Call。为了支持这一点,它具有a的概念,该概念CallAdapter应该知道如何将a调整Call<Simple>为a Simple

RxJavaCallAdapterFactory仅当您尝试返回时,使用才有用rx.Observable<Simple>

最简单的解决方案是返回CallRetrofit期望的结果。CallAdapter.Factory如果确实需要,也可以编写一个。


1
是的,这确实是正确的答案:(。我从一开始就知道这Call<Simple>是它的工作方式。但是,正如我的问题所述,我更喜欢只返回Simple(就像早期版本一样)。我的结论是:没有额外的代码,是不可能的
rmuller

您提供的链接已Call<Simple> 断开。什么包裹Simple属于?
shyam

感谢您的来信@shyam。我已经更新了链接。Simple是OP的问题中提到的课程。链接是Call<T>
Hosam Aly

75

Kotlin协程的情况下,当我忘记将api服务函数标记为suspendCoroutineScope(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>
}

53

添加依赖项:

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>


7
我知道将Simple更改为Call <Simple>可以解决问题。但是,我不想将类型引入Call服务接口
rmuller

您还可以使用CompletableFuture查看stackoverflow.com/questions/32269064/...
约翰内斯Barop

38

使用新的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请求。似乎没有他们做广告那么简单。也许他们应该记录更多。
VladoPandžić2015年

如果您使用的是Retrofit 2.0,请使用Retrofit而不是RestAdapter。
Himanshu Virmani 2015年

5
RxJavaCallAdapterFactory需要来自同一存储库的adapter-rxjava工件。 compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
Damien Diehl

3
进行改造2,请确保您使用正确的依赖关系,com.squareup.retrofit2:adapter-rxjava:2.1.0以及 com.squareup.retrofit2:converter-gson:2.1.0
George Papas

16

如果要使用 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
                }
            }
        };
    }
}

然后SynchronousCallAdapterFactory在Retrofit中简单注册即可解决您的问题。

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 2016年

“实现CallAdapter.Factory”这是一个类而不是接口吗?
ozmank

@ozmank在版本中2.0.0-beta3它是一个接口,在版本中2.1.0它是一个类。为了更实际,我编辑了代码。谢谢。
Mateusz Korwel '16

@MateuszKorwel它总是会抛出新的RuntimeException(e)!我想返回String而不是Simple。
Dr.jacky '17

3
谢谢你张贴这个。我围绕此处理Simple getSimple()Response<Simple> getSimple()请求创建了一个库:github.com/jaredsburrows/retrofit2-synchronous-adapter
Jared Burrows

13

为改装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 2015年

1
在创建适配器时也请确保添加以下行:.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
Shayan_Aryan

无法解决:com.squareup.retrofit:adapter-rxjava:2.1.0
ozmank

1
@ozmank它的retrofit2,我也更新了我的答案。请尝试一下
rahulrv

4

以我为例

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

有了这个

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

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


2

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

2

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"

祝好运


1

只是为了使正在迁移,不使用Rx或需要同步呼叫的人员更清楚“呼叫”示例-呼叫本质上是替换(包装)响应,意思是:

Response<MyObject> createRecord(...);

变成

Call<MyObject> createRecord(...);

并不是

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

(仍然需要适配器)


然后,该呼叫将允许您仍然使用,isSuccessful因为它实际上会返回响应。因此,您可以执行以下操作:

myApi.createRecord(...).execute().isSuccessful()

或按如下方式访问您的Type(MyObject):

MyObject myObj = myApi.createRecord(...).execute().body();

1
public interface SimpleService {

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

}

与网络的通信是通过单独的线程完成的,因此您应该使用它来更改“简单”。

public interface SimpleService {

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

}

1

就我而言

com.squareup.retrofit2:adapter-rxjava:2.5.0 //notice rxjava

代替

com.squareup.retrofit2:adapter-rxjava2:2.5.0 //notice rxjava2

您应该在使用com.squareup.retrofit2:adapter-rxjava2:2.5.0时使用io.reactivex.rxjava2


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
    }

}

-2

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

希望能帮助到你!


1
这与我的问题完全相同的配置。因此,不会解决任何问题:)
rmuller 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.