Retrofit 2.0 ve RxJava'yı kullanarak yanıt durum kodunu alın


108

Retrofit 2.0'a yükseltmeye ve android projeme RxJava eklemeye çalışıyorum. Bir api araması yapıyorum ve sunucudan bir hata yanıtı olması durumunda hata kodunu almak istiyorum.

Observable<MyResponseObject> apiCall(@Body body);

Ve RxJava çağrısında:

myRetrofitObject.apiCall(body).subscribe(new Subscriber<MyResponseObject>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onNext(MyResponseObject myResponseObject) {
           //On response from server
        }
    });

Retrofit 1.9'da RetrofitError hala mevcuttu ve aşağıdakileri yaparak durumu elde edebilirdik:

error.getResponse().getStatus()

Bunu RxJava kullanarak Retrofit 2.0 ile nasıl yaparsınız?

Yanıtlar:


185

Yaptığınız gibi API çağrısını bildirmek yerine:

Observable<MyResponseObject> apiCall(@Body body);

Bunu şu şekilde de ilan edebilirsiniz:

Observable<Response<MyResponseObject>> apiCall(@Body body);

Daha sonra aşağıdaki gibi bir Aboneye sahip olacaksınız:

new Subscriber<Response<StartupResponse>>() {
    @Override
    public void onCompleted() {}

    @Override
    public void onError(Throwable e) {
        Timber.e(e, "onError: %", e.toString());

        // network errors, e. g. UnknownHostException, will end up here
    }

    @Override
    public void onNext(Response<StartupResponse> startupResponseResponse) {
        Timber.d("onNext: %s", startupResponseResponse.code());

        // HTTP errors, e. g. 404, will end up here!
    }
}

Böylece hata kodlu sunucu yanıtları da gönderilecek onNextve kodu arayarak alabilirsiniz reponse.code().

http://square.github.io/retrofit/2.x/retrofit/retrofit/Response.html

DÜZENLEME: Tamam, sonunda e-nouri'nin yorumlarında ne söylediğini araştırmaya başladım, yani sadece 2xx kodları bunu yapacak onNext. İkimizin de haklı olduğu ortaya çıktı:

Çağrı böyle ilan edilirse:

Observable<Response<MyResponseObject>> apiCall(@Body body);

hatta bu

Observable<Response<ResponseBody>> apiCall(@Body body);

onNexthata kodlarına bakılmaksızın tüm yanıtlar verilecektir . Bu mümkündür çünkü her şey ResponseRetrofit ile bir nesneye sarılır .

Öte yandan, çağrı şu şekilde ilan edilirse:

Observable<MyResponseObject> apiCall(@Body body);

veya bu

Observable<ResponseBody> apiCall(@Body body);

gerçekten de sadece 2xx yanıtları gidecek onNext. Diğer her şey bir içine sarılıp HttpExceptionadresine gönderilecek onError. Hangi nedeniyle de olmadan, mantıklı Response, ne sarmalayıcı gerektiğini yayılacaktır onNext? İsteğin başarılı olmadığı göz önüne alındığında, yayılması gereken tek mantıklı şey null...


17
4xx HTTP kodlarını arayan kişiler, onError'da HttpException olarak sona erecektir. onNext yalnızca 2xx içerecektir.
e-nouri

2
Bu ilginç ... Tekrar kontrol ettim ( gist.github.com/DavidMihola/17a6ea373b9312fb723b ) ve denediğim tüm kodlar onNext404 vb. Dahil oldu. Retrofit v2.0.0-beta3 kullandım.
david.mihola

@ e-nouri: Cevabıma yorumunuzu dikkate alan bir paragraf ekledim!
david.mihola

1
@ david.mihola Yapı Güçlendirme ekleme işleviyle ise GsonConverterFactory, tıpkı Retrofit retrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()), nasıl orijinal yanıt almak için?
Honghe.Wu

1
Hata işlemenin yanı sıra, gövdeyle birlikte gelen herhangi bir yanıt üstbilgisini inceleyebilmeyi isteyebileceğinizi düşünüyorum - bu da yalnızca Response. Ben de nadiren kullanırım - ama var olduğunu bilmenin iyi olduğunu düşünüyorum.
david.mihola

112

OnError yönteminin içine kodu almak için bunu koyun

((HttpException) e).code()

7
Bu, SO'da gördüğüm en küçümsenen cevaplardan biri olabilir. Bu dahice. Cevapla yapmanız gerekebilecek her şeyi yapabilirsiniz HttpException. RxJava kullanıyorum ve bir HTTP 400 BAD REQUEST. Çok teşekkür ederim!
GabrielOshiro

29
Daha önce bunun bir HttpException örneği olup olmadığını kontrol ettiğinizden emin olun, çünkü NetworkErrors IOExceptions olacaktır ve bir durum koduna sahip olmayacaktır.
Benjamin Mesing

@BenjaminMesing, NetworkError hakkında şunları söyledi: abone olmadan önce Rx'inizde daha fazla aşağı akış operatörü (map / flatMap / forEach vb.) Yapıyorsanız, o zaman bir dizi olası istisna türü olabilir ve mutlaka ağ talebi.
Mark Keen

java.lang.ClassCastException: java.lang.Throwable, retrofit2.HttpException için dönüştürülemez
Someone Somewhere

7

Sen itibariyle dikkat etmelidir Retrofit2 kodu ile tüm yanıtlar 2xx OnNext () geri çağırma ve geri kalanından adı verilecek HTTP kodları 4xx gibi 5xx çağrılacak onError () kullanarak geri arama Kotlin ben oldum gibi bir şey ile geldi Bu OnError () :

mViewReference?.get()?.onMediaFetchFinished(downloadArg)
  if (it is HttpException) {
    val errorCode = it.code()
    mViewReference?.get()?.onMediaFetchFailed(downloadArg,when(errorCode){
      HttpURLConnection.HTTP_NOT_FOUND -> R.string.check_is_private
      else -> ErrorHandler.parseError(it)
    })
  } else {
    mViewReference?.get()?.onMediaFetchFailed(downloadArg, ErrorHandler.parseError(it))
  }
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.