Không thể tạo bộ điều hợp cuộc gọi cho ví dụ lớp.


87

Tôi đang sử dụng trang bị thêm 2.0.0-beta1 với SimpleXml. Tôi muốn truy xuất tài nguyên Đơn giản (XML) từ dịch vụ REST. Marshalling / Unmarshalling đối tượng Simple với SimpleXML hoạt động tốt.

Khi sử dụng mã này (mã dạng chuyển đổi trước 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"));

Dịch vụ:

public interface SimpleService {

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

}

Tôi nhận được ngoại lệ này:

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)

Tôi đang thiếu cái gì? Tôi biết rằng gói kiểu trả về bởi một Callhoạt động. Nhưng tôi muốn dịch vụ trả về các đối tượng nghiệp vụ dưới dạng loại (và hoạt động ở chế độ đồng bộ).

CẬP NHẬT

Sau khi thêm các phần phụ thuộc bổ sung và .addCallAdapterFactory(RxJavaCallAdapterFactory.create())theo đề xuất của các câu trả lời khác nhau, tôi vẫn gặp lỗi này:

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


Đối với những người đang sử dụng Coroutine, hãy kiểm tra câu trả lời @chatlanin
NJ

Câu trả lời:


66

Câu trả lời ngắn gọn: trở lại Call<Simple>trong giao diện dịch vụ của bạn.

Có vẻ như Retrofit 2.0 đang cố gắng tìm cách tạo đối tượng proxy cho giao diện dịch vụ của bạn. Nó mong bạn viết điều này:

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

Tuy nhiên, nó vẫn muốn chơi đẹp và linh hoạt khi không muốn quay lại a Call. Để hỗ trợ điều này, nó có khái niệm về a CallAdapter, được cho là biết cách điều chỉnh a Call<Simple>thành a Simple.

Việc sử dụng RxJavaCallAdapterFactorychỉ hữu ích nếu bạn đang cố gắng quay trở lại rx.Observable<Simple>.

Giải pháp đơn giản nhất là trả về một Callnhư Retrofit mong đợi. Bạn cũng có thể viết một CallAdapter.Factorynếu bạn thực sự cần nó.


1
Vâng, đây thực sự là câu trả lời đúng :(. Tôi biết ngay từ đầu đó Call<Simple>là cách nó hoạt động. Tuy nhiên, như đã nêu trong câu hỏi của tôi, sở thích của tôi là chỉ quay lại Simple(như trường hợp của phiên bản trước). Kết luận của tôi là :. không thể không có mã thêm
rmuller

Liên kết bạn đã cung cấp Call<Simple> bị hỏng. Gói nào Simplethuộc về?
shyam

Cảm ơn vì ghi chú @shyam. Tôi đã cập nhật các liên kết. Simplelà lớp được đề cập trong câu hỏi của OP. Liên kết là để Call<T>.
Hosam Aly

78

Trong trường hợp Kotlincoroutines , tình huống này đã xảy ra khi tôi quên đánh dấu hàm dịch vụ api suspendkhi tôi gọi hàm này từ CoroutineScope(Dispatchers.IO).launch{}:

Sử dụng:

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

You save my live bro s2
Guilherme Ramos

53

thêm phụ thuộc:

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'

tạo bộ điều hợp của bạn theo cách này:

Retrofit rest = new Retrofit.Builder()
    .baseUrl(endpoint)
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    .addConverterFactory(SimpleXmlConverterFactory.create())
    .build();

addCallAdapterFactory ()addConverterFactory ()cả hai đều cần được gọi.

Dịch vụ:

public interface SimpleService {

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

}

Sửa đổi Simplethành Call<Simple>.


7
Tôi biết rằng việc thay đổi Simple to Call <Simple> thực hiện được một mẹo nhỏ. Tuy nhiên, tôi không muốn giới thiệu loại Callgiao diện dịch vụ
rmuller

Bạn cũng có thể sử dụng CompletableFutureXem stackoverflow.com/questions/32269064/…
Johannes Barop

38

Với Retrofit mới (2. +), bạn cần thêm addCallAdapterFactory có thể là một bình thường hoặc một RxJavaCallAdapterFactory (cho Observables). Tôi nghĩ bạn có thể thêm nhiều hơn cả hai. Nó tự động kiểm tra cái nào để sử dụng. Xem một ví dụ làm việc bên dưới. Bạn cũng có thể kiểm tra liên kết này để biết thêm chi tiết.

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

1
Liên kết tuyệt vời! Sẽ kiểm tra sau.
rmuller

1
Trong tài liệu vẫn có RestAdapter và không có ví dụ về cách thực hiện yêu cầu đơn giản nhất với Retrofit 2.0. Tôi gặp lỗi Không thể giải quyết RxJavaCallAdapterFactory. Đã dành vài giờ để thực hiện yêu cầu http android đơn giản nhất. Có vẻ như nó không quá đơn giản như họ quảng cáo. Có lẽ họ nên ghi chép nhiều hơn một chút.
Vlado Pandžić

Sử dụng Retrofit thay vì RestAdapter nếu bạn đang sử dụng Retrofit 2.0.
Himanshu Virmani,

5
RxJavaCallAdapterFactory yêu cầu tạo tác bộ điều hợp-rxjava từ cùng một kho. compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
Damien Diehl

3
đối với trang bị thêm2, hãy đảm bảo bạn sử dụng các phụ thuộc chính xác com.squareup.retrofit2:adapter-rxjava:2.1.0com.squareup.retrofit2:converter-gson:2.1.0
George Papas

16

Nếu bạn muốn sử dụng retrofit2và bạn không muốn luôn trả về retrofit2.Call<T>, bạn phải tạo cho riêng mình CallAdapter.Factorykiểu trả về đơn giản như bạn mong đợi. Mã đơn giản có thể trông như sau:

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

Sau đó, đăng ký đơn giản SynchronousCallAdapterFactorytrong Retrofit sẽ giải quyết được vấn đề của bạn.

Retrofit rest = new Retrofit.Builder()
        .baseUrl(endpoint)
        .addConverterFactory(SimpleXmlConverterFactory.create())
        .addCallAdapterFactory(SynchronousCallAdapterFactory.create())
        .build();

Sau đó, bạn có thể trả về loại đơn giản mà không cần retrofit2.Call.

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

Thật sự cảm ơn. Bạn có biết có cách nào để tạo bộ điều hợp cuộc gọi không đồng bộ không? vì vậy tôi có thể gọi một dịch vụ như vậy: service.getSimple ("id", new Adapter () {onFail () {} onSuccess () {}} thay vì sử dụng enqueue () và callback?
markov00

"thực hiện CallAdapter.Factory" Đây là một lớp không phải là một giao diện?
ozmank

@ozmank Trong phiên bản, 2.0.0-beta3nó là một giao diện, bây giờ trong phiên bản 2.1.0nó là một lớp. Tôi đã chỉnh sửa mã của mình, để thực tế hơn. Cảm ơn.
Mateusz Korwel

@MateuszKorwel Nó luôn được ném RuntimeException (e) mới! Tôi muốn trả về Chuỗi thay vì Đơn giản.
Dr.jacky

3
Cảm ơn bạn đã đăng bài này. Tôi đã tạo một thư viện xung quanh việc xử lý này Simple getSimple()Response<Simple> getSimple()các yêu cầu: github.com/jaredsburrows/retrofit2-synchronous-adapter .
Jared Burrows

13

Thêm các phần phụ thuộc sau cho trang bị thêm 2

 compile 'com.squareup.retrofit2:retrofit:2.1.0'

cho GSON

 compile 'com.squareup.retrofit2:converter-gson:2.1.0'

cho những người có thể quan sát

compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'

Trong trường hợp của bạn đối với XML, bạn sẽ phải bao gồm các phần phụ thuộc sau

 compile 'com.squareup.retrofit2:converter-simplexml:2.1.0'

Cập nhật cuộc gọi dịch vụ như bên dưới

final Retrofit rest = new Retrofit.Builder()
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    .addConverterFactory(SimpleXmlConverterFactory.create())
    .baseUrl(endpoint)
    .build();
SimpleService service = rest.create(SimpleService.class);

Điều này cũng giống như thiết lập của tôi.
rmuller

1
cũng hãy nhớ thêm dòng này khi tạo bộ điều hợp: .addCallAdapterFactory (RxJavaCallAdapterFactory.create ())
Shayan_Aryan

Thất bại trong việc quyết tâm: com.squareup.retrofit: adapter-rxjava: 2.1.0
ozmank

1
@ozmank trang bị thêm của nó2, tôi cũng đã cập nhật câu trả lời của mình. Vui lòng dùng thử
rahulrv

4

trong trường hợp của tôi sử dụng cái này

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

Với cái này

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

đã giải quyết vấn đề khi không có gì khác hoạt động


2

Nếu bạn không sử dụng RxJava đúng cách, không có ý nghĩa gì khi thêm RxJava chỉ để trang bị thêm. 2.5.0có hỗ trợ tích CompletableFuturehợp sẵn mà bạn có thể sử dụng mà không cần thêm bất kỳ thư viện hoặc bộ điều hợp nào khác.

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

Sử dụng:

Retrofit.Builder()
   .addConverterFactory(SimpleXmlConverterFactory.create())
   .baseUrl("https://api.example.com")
   .build()
   .create(Api::class.java)

2

IllegalArgumentException: Không thể tạo bộ điều hợp cuộc gọi cho lớp java.lang.Object

Câu trả lời ngắn gọn: Tôi đã giải quyết nó bằng những thay đổi sau

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"

Chúc may mắn


1

Chỉ để làm cho các ví dụ Cuộc gọi rõ ràng hơn cho những người đang di chuyển, không sử dụng Rx hoặc những người muốn các cuộc gọi đồng bộ - Cuộc gọi về cơ bản thay thế (kết thúc) Phản hồi, nghĩa là:

Response<MyObject> createRecord(...);

trở thành

Call<MyObject> createRecord(...);

và không

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

(vẫn sẽ yêu cầu bộ điều hợp)


Sau đó, Cuộc gọi sẽ cho phép bạn vẫn sử dụng isSuccessfulvì nó thực sự trả về một Phản hồi. Vì vậy, bạn có thể làm điều gì đó như:

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

Hoặc truy cập Loại (MyObject) của bạn như:

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

1
public interface SimpleService {

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

}

Giao tiếp với mạng được thực hiện bằng chuỗi riêng biệt, vì vậy bạn nên thay đổi Đơn giản của mình bằng đó.

public interface SimpleService {

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

}

1

Trong trường hợp của tôi, tôi đã sử dụng

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

thay vì

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

bạn nên sử dụng com.squareup.retrofit2:adapter-rxjava2:2.5.0khi sử dụngio.reactivex.rxjava2


0

Bạn có thể triển khai Callback, lấy chức năng Simple from onResponse.

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

Cách tôi đã khắc phục sự cố này là thêm tệp này vào tệp gradle ứng dụng, nếu cấu hình không được đặt sẽ có xung đột, có thể điều này sẽ được khắc phục trong bản phát hành ổn định của thư viện:

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

và tạo bộ điều hợp của bạn theo cách này:

  Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(endPoint)
            .addConverterFactory(SimpleXmlConverterFactory.create())
            .build();

Hy vọng nó giúp!


1
Đây chính xác là cấu hình giống như trong câu hỏi của tôi. Vì vậy, không giải quyết được bất cứ điều gì :)
rmuller
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.