【问题标题】:Unable to create call adapter for class example.Simple无法为类示例创建调用适配器。简单
【发布时间】:2015-11-22 23:57:14
【问题描述】:

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

【问题讨论】:

标签: java rest retrofit simple-framework


【解决方案1】:

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

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

【讨论】:

  • 很好的链接!稍后会检查。
  • 在文档中仍然有 RestAdapter 并且没有示例如何使用 Retrofit 2.0 发出最简单的请求。我收到错误无法解析 RxJavaCallAdapterFactory。花了几个小时制作最简单的 android http 请求。似乎没有他们宣传的那么简单。也许他们应该记录更多。
  • 如果您使用的是 Retrofit 2.0,请使用 Retrofit 而不是 RestAdapter。
  • RxJavaCallAdapterFactory 需要来自同一个 repo 的 adapter-rxjava 工件。 compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
  • 对于retrofit2,确保使用正确的依赖关系com.squareup.retrofit2:adapter-rxjava:2.1.0com.squareup.retrofit2:converter-gson:2.1.0
【解决方案2】:

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

【讨论】:

  • 这和我的设置一样。
  • 在创建适配器时也一定要加上这一行:.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
  • 无法解决:com.squareup.retrofit:adapter-rxjava:2.1.0
  • @ozmank its retrofit2 ,我也更新了我的答案。请尝试一下
【解决方案3】:

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

希望对你有帮助!

【讨论】:

  • 这与我的问题中的配置完全相同。所以,没有解决任何问题:)
【解决方案4】:

添加依赖:

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&lt;Simple&gt;

【讨论】:

【解决方案5】:

简答:在您的服务接口中返回Call&lt;Simple&gt;

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

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

但是,当您不想返回 Call 时,它仍然希望表现出色并保持灵活性。为了支持这一点,它具有CallAdapter 的概念,它应该知道如何将Call&lt;Simple&gt; 改编为Simple

RxJavaCallAdapterFactory 的使用仅在您尝试返回 rx.Observable&lt;Simple&gt; 时才有用。

最简单的解决方案是按照 Retrofit 的预期返回 Call。如果你真的需要,也可以写CallAdapter.Factory

【讨论】:

  • 是的,这确实是正确的答案:(。我从一开始就知道Call&lt;Simple&gt; 是它的工作方式。但是,正如我的问题中所述,我的偏好是只返回Simple (就像早期版本的情况一样)。我的结论是:没有额外的代码是不可能的。
  • 您为Call&lt;Simple&gt; 提供的链接已损坏。 Simple 属于什么包?
  • 感谢@shyam 的留言。我已经更新了链接。 Simple 是 OP 问题中提到的类。链接是Call&lt;T&gt;
【解决方案6】:

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

}

【讨论】:

    【解决方案7】:

    如果你想使用retrofit2 并且你不想总是返回retrofit2.Call&lt;T&gt;,你必须创建你自己的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() 和回调?
    • "implements CallAdapter.Factory" 这是一个类而不是一个接口?
    • @ozmank 在2.0.0-beta3 版本中它是一个接口,现在在2.1.0 版本中它是一个类。我编辑了我的代码,更实际。谢谢。
    • @MateuszKorwel 它总是抛出新的 RuntimeException(e)!我想返回 String 而不是 Simple。
    • 感谢您发布此信息。我围绕这个处理 Simple getSimple()Response&lt;Simple&gt; getSimple() 请求创建了一个库:github.com/jaredsburrows/retrofit2-synchronous-adapter
    【解决方案8】:

    在我的情况下使用这个

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

    有了这个

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

    在没有其他方法的情况下解决了问题

    【讨论】:

      【解决方案9】:

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

      Response<MyObject> createRecord(...);
      

      变成

      Call<MyObject> createRecord(...);
      

      而不是

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

      (仍然需要适配器)


      然后调用将允许您仍然使用isSuccessful,因为它实际上会返回一个响应。所以你可以这样做:

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

      或访问您的类型(MyObject),如:

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

      【讨论】:

        【解决方案10】:
        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);
        
        }
        

        【讨论】:

          【解决方案11】:

          就我而言,我使用了

          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

          【讨论】:

            【解决方案12】:

            如果你没有使用 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)
            

            【讨论】:

              【解决方案13】:

              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"
              

              祝你好运

              【讨论】:

                【解决方案14】:

                Kotlincoroutines 的情况下,当我从 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>
                }
                

                【讨论】:

                • 你救了我的现场兄弟 s2
                • 在使用 Coroutines 时,我们必须将 suspend 与您的 Function 一起使用。这有助于感谢好友
                • 它对我有用 tnx。添加suspend是解决这个错误的方法
                • 你好@chatlanin,我是 MVVM 和 corotuine 的新手,我遇到了同样的问题。你能帮帮我吗。这是我的代码 github.com/diptoroy/RetrofitKotlin
                • 节省了我的时间,你 :)
                【解决方案15】:

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

                1. 这是ApiInterface.java

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

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

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

                  暂停有趣的getConnectionKt():响应{ 返回 apiInterface.ConnectionKt().awaitResponse() } }

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

                val 数据 = withContext(ioDispatcher) { val 结果 = apiTemporary.getConnectionKt() 如果(结果.isSuccessful){ Resource.Success(result.body()) } 别的 { Resource.Error("服务器错误,请重试") } } _connection.value = 数据

                所以,ApiTemporary 将有助于将它们从 Java 转换为使用 Coroutines 的 Kotlin

                【讨论】:

                  【解决方案16】:

                  我通过在 gradle 中将改造版本更新到 2.9.0 解决了

                  【讨论】:

                    【解决方案17】:

                    如果您的 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)
                            }
                        }
                    
                    }
                    

                    【讨论】:

                      【解决方案18】:

                      对于这种情况:

                      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 错误。

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 2021-06-26
                        • 2017-09-12
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2017-04-19
                        相关资源
                        最近更新 更多