Sınıf örneği için çağrı bağdaştırıcısı oluşturulamıyor.


91

SimpleXml ile güçlendirilmiş 2.0.0-beta1 kullanıyorum. Bir REST hizmetinden Basit (XML) bir kaynak almak istiyorum. SimpleXML ile Basit nesneyi Marshalling / Unmarshalling iyi çalışıyor.

Bu kodu kullanırken (2.0.0 kod öncesi dönüştürülmüş biçim):

final Retrofit rest = new Retrofit.Builder()
    .addConverterFactory(SimpleXmlConverterFactory.create())
    .baseUrl(endpoint)
    .build();
SimpleService service = rest.create(SimpleService.class);
LOG.info(service.getSimple("572642"));

Hizmet:

public interface SimpleService {

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

}

Bu istisnayı anlıyorum:

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)

Neyi kaçırıyorum? Dönüş türünü bir Callesere göre sarmayı biliyorum . Ancak hizmetin iş nesnelerini tür olarak döndürmesini (ve eşitleme modunda çalışarak) istiyorum.

GÜNCELLEME

Ekstra bağımlılıkları ekledikten sonra ve .addCallAdapterFactory(RxJavaCallAdapterFactory.create())farklı cevapların önerdiği gibi, hala bu hatayı alıyorum:

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


1
Coroutine kontrol kullananlar için @chatlanin answer
NJ

Yanıtlar:


68

Kısa cevap: Call<Simple>servis arayüzünüzde geri dönün .

Retrofit 2.0, hizmet arayüzünüz için proxy nesnesi oluşturmanın bir yolunu bulmaya çalışıyor gibi görünüyor. Sizden şunu yazmanızı bekliyor:

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

Bununla birlikte, a döndürmek istemediğinizde yine de güzel oynamak ve esnek olmak istiyor Call. Bunu desteklemek için, bir kavramı vardır CallAdapterbir uyum için bilmek gerekiyordu, Call<Simple>bir içine Simple.

Kullanımı RxJavaCallAdapterFactoryyalnızca geri dönmeye çalışıyorsanız yararlıdır rx.Observable<Simple>.

En basit çözüm, CallRetrofit'in beklediği şekilde bir geri döndürmektir . CallAdapter.FactoryGerçekten ihtiyacınız olursa bir de yazabilirsiniz .


1
Evet, bu gerçekten doğru cevap :(. Bunun Call<Simple>nasıl çalıştığını başından beri biliyorum . Ancak, sorumda belirtildiği gibi tercihim sadece geri dönmek Simple(önceki sürümde olduğu gibi). Sonuç : ekstra kod olmadan mümkün değil.
rmuller

Sağladığınız bağlantı Call<Simple> bozuk. Hangi pakete Simpleaittir?
shyam

@Shyam notu için teşekkürler. Bağlantıları güncelledim. SimpleOP'nin sorusunda bahsedilen sınıftır. Bağlantı Call<T>.
Hosam Aly

94

Kotlin ve coroutines söz konusu olduğunda, bu durum, api hizmet işlevini suspendşu işlevden çağırdığım gibi işaretlemeyi unuttuğumda gerçekleşti CoroutineScope(Dispatchers.IO).launch{}:

Kullanım:

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

Canlı kardeşimi kurtardın
Guilherme Ramos

Coroutines'i kullanırken, İşlevinizle birlikte askıya almayı kullanmamız gerekir. bu teşekkürler dostum
Abubakar Rafi

benim için çalıştı tnx. askıya alma eklemek bu hatanın çözümü
mmdreza baqalpour

53

bağımlılıklar ekleyin:

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'

adaptörünüzü şu şekilde oluşturun:

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

addCallAdapterFactory () ve addConverterFactory () her ikisinin de çağrılması gerekiyor.

Hizmet:

public interface SimpleService {

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

}

Değiştir Simpleetmek Call<Simple>.


7
<Simple> Basitçe Arama'yı değiştirmenin işin yarayacağını biliyorum. Ancak, Callhizmet arayüzüne tür tanıtmak istemiyorum
rmuller


38

Yeni Retrofit (2. +) ile, normal bir veya bir RxJavaCallAdapterFactory (Gözlemlenebilirler için) olabilen addCallAdapterFactory eklemeniz gerekir. Bence ikisinden de fazlasını ekleyebilirsin. Hangisinin kullanılacağını otomatik olarak kontrol eder. Aşağıdaki çalışan bir örneğe bakın. Daha fazla ayrıntı için bu bağlantıya da bakabilirsiniz.

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

1
Harika bağlantı! Daha sonra kontrol edecek.
rmuller

1
Belgelerde hala RestAdapter var ve Retrofit 2.0 ile en basit talebin nasıl yapılacağına dair hiçbir örnek yok. Hata alıyorum RxJavaCallAdapterFactory çözülemedi. En basit android http isteğini yapmak için birkaç saat harcadı. Görünüşe göre reklam verdikleri kadar basit değil. Belki biraz daha belgelemeliler.
Vlado Pandžić

Retrofit 2.0 kullanıyorsanız RestAdapter yerine Retrofit kullanın.
Himanshu Virmani

5
RxJavaCallAdapterFactory, aynı depodan adaptör-rxjava yapısını gerektirir. compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
Damien Diehl

3
retrofit2 için doğru bağımlılıkları kullandığınızdan emin olun com.squareup.retrofit2:adapter-rxjava:2.1.0ve com.squareup.retrofit2:converter-gson:2.1.0
George Papas

16

Kullanmak istiyorsanız retrofit2ve her zaman geri dönmek istemiyorsanız retrofit2.Call<T>, CallAdapter.Factorybeklediğiniz gibi basit türü döndüren kendi türünüzü oluşturmanız gerekir . Basit kod şöyle görünebilir:

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

O zaman basit bir şekilde SynchronousCallAdapterFactoryRetrofit'e kaydedin, sorununuzu çözmelidir.

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

Bundan sonra basit tipe çevirmeden dönebilirsiniz retrofit2.Call.

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

Harika teşekkürler. Eşzamansız çağrı bağdaştırıcısı oluşturmanın bir yolu olup olmadığını biliyor musunuz? enqueue () ve geri
aramayı

"CallAdapter.Factory'yi uygular" Bu bir sınıf, bir arabirim değil mi?
ozmank

@ozmank Versiyonda 2.0.0-beta3bir arayüz, şimdi versiyonda 2.1.0bir sınıf. Daha güncel olması için kodumu düzenledim. Teşekkürler.
Mateusz Korwel

@MateuszKorwel Her zaman yeni RuntimeException (e) atar! Simple yerine String'i iade etmek istiyorum.
Dr.jacky

3
Bunu gönderdiğiniz için teşekkür ederiz. Bu işlem Simple getSimple()ve Response<Simple> getSimple()istekler etrafında bir kitaplık oluşturdum : github.com/jaredsburrows/retrofit2-synchronous-adapter .
Jared Burrows

13

Güçlendirme 2 için aşağıdaki bağımlılıkları ekleyin

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

GSON için

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

gözlemlenebilirler için

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

XML durumunda, aşağıdaki bağımlılıkları eklemeniz gerekir

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

Servis çağrısını aşağıdaki gibi güncelleyin

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

Bu benim kurulumumla aynı.
rmuller

1
ayrıca bağdaştırıcı oluştururken bu satırı eklediğinizden emin olun: .addCallAdapterFactory (RxJavaCallAdapterFactory.create ())
Shayan_Aryan

Çözümlenemedi: com.squareup.retrofit: adapter-rxjava: 2.1.0
ozmank

1
@ozmank retrofit2, cevabımı da güncelledim. Lütfen deneyin
rahulrv

5

IllegalArgumentException: java.lang.Object sınıfı için çağrı bağdaştırıcısı yaratılamıyor

Kısa cevap: Aşağıdaki değişikliklerle çözdüm

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"

İyi şanslar


4

benim durumumda bunu kullanarak

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

Bununla

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

başka hiçbir şey işe yaramadığında sorunu çözdü


2

RxJava kullanmıyorsanız, RxJava'yı sadece iyileştirme için eklemenin bir anlamı yoktur. başka bir kitaplık veya bağdaştırıcı eklemeden kullanabileceğiniz yerleşik 2.5.0desteği vardır 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>
}

Kullanım:

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

1

Sadece Arama örneklerini göç eden, Rx kullanmayan veya eşzamanlı aramalar isteyen kişiler için daha net hale getirmek için - Arama esasen Yanıtı değiştirir (tamamlar), yani:

Response<MyObject> createRecord(...);

olur

Call<MyObject> createRecord(...);

ve yok

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

(hala bir adaptör gerektirecektir)


Çağrı, isSuccessfulaslında bir Yanıt döndürdüğü için hala kullanmanıza izin verecektir . Böylece şöyle bir şey yapabilirsiniz:

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

Veya Türünüze (MyObject) şu şekilde erişin:

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

1
public interface SimpleService {

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

}

Ağ ile iletişim ayrı bir iş parçacığı ile yapılır, bu nedenle Simple'ınızı bununla değiştirmelisiniz.

public interface SimpleService {

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

}

1

Benim durumumda kullandım

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

onun yerine

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

Kullandığınız olmalıdır com.squareup.retrofit2:adapter-rxjava2:2.5.0kullanırkenio.reactivex.rxjava2


0

Bir Geri Çağırma uygulayabilir, Simple'ı onResponse işlevinden alabilirsiniz.

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

Bu sorunu çözme şeklim, bunu uygulama gradle dosyasına eklemekti, yapılandırma ayarlanmadıysa çakışmalar olacak, belki de bu, kütüphanenin kararlı sürümünde düzeltilecek:

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

ve adaptörünüzü şu şekilde oluşturun:

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

Umarım yardımcı olur!


1
Bu, sorumdakiyle tamamen aynı konfigürasyon. Yani, hiçbir şeyi çözmez :)
rmuller
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.