2015-05-10 17 views
5

Retrofit'in sunucu yanıtına bağlı olarak özel istisnalar geliştirmesini istiyorum. Aşağıdaki yapıda Örneğin:RxJava ve Güçlendirme - Sunucu yanıtına bağlı olarak özel istisnaları yükseltme

{ 
"code":0, 
"message":"OK", 
"data":{....} 
} 

code 0'dan dışında bir Nasıl Sonradan montaj ve Rx kullanarak mümkün olup olmadığını aboneler için bir istisna istersiniz? Bu mantığı sadece bir kez yazmayı tercih ederim ve retrofit tarafından iade edilen tüm gözlenebilirlere başvurmayı tercih ederim.

cevap

6

Kod 0'dan başka bir şey varsa aboneler için bir istisna oluşturmak istiyorum. Retrofit ve Rx kullanarak nasıl mümkündür?

api.request().flatMap(response -> { 
    if (response.getCode() != 0) { 
     return Observable.error(new Exception("Remote error occurred")); 
    } 

    return Observable.just(response); 
}); 

ben çok sadece bir kez bu mantığı yazmayı tercih ve güçlendirme tarafından döndürülen tüm gözlenebilirlere uygulanan olurdu:

Bir Observable.flatMap operatörünü kullanabilirsiniz.

Maalesef retrofit ve rx-java kullanarak bunu yapmak için bir yol yoktur. Her retrofit numaralı çağrı için yukarıdaki kodu yazmak için numarasına sahip olursunuz. Yapabileceğiniz tek şey, Observable.compose yöntemini kullanmak ve yazmak zorunda olduğunuz boilerplate miktarını azaltmaktır.

api.request().compose(new ResponseTransformer<Response>()); 

Ve burada ResponseTransformer sınıftır:

public static class ResponseTransformer<T extends Response> implements Observable.Transformer<T, T> { 
    @Override 
    public Observable<T> call(final Observable<T> observable) { 
     return observable.flatMap(response -> { 
      if (response.getCode() != 0) { 
       return Observable.error(new Exception("Remote error occurred")); 
      } 

      return Observable.just(response); 
     }); 
    } 
} 

GÜNCELLEME

Eh, dediğim gibi, orada sadece retrofit ve rxjava kullanarak Demirbaş kodu önlemek için hiçbir yolu yoktur, ancak dynamic proxies ile geçici çözüm (compose aramanıza gerek kalmayacağını unutmayın):

final Api api = restAdapter.create(Api.class); 

final ClassLoader loader = api.getClass().getClassLoader(); 
final Class<?>[] interfaces = api.getClass().getInterfaces(); 

final Api proxy = (Api) Proxy.newProxyInstance(loader, interfaces, new ResponseInvocationHandler(api)); 

proxy.request().subscribe(response -> { 
    System.out.println("Success!"); 
}); 

ResponseInvocationHandler sınıfı:

public static class ResponseInvocationHandler implements InvocationHandler { 
    private final Object target; 

    public ResponseInvocationHandler(final Object target) { 
     this.target = target; 
    } 

    @Override 
    @SuppressWarnings({"unchecked"}) 
    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { 
     final Object result = method.invoke(target, args); 

     if (result instanceof Observable) { 
      return Observable.class.cast(result).compose(new ResponseTransformer<>()); 
     } 

     return result; 
    } 
} 
+0

sayesinde – Nima

+1

çok yararlı o da yapabilirdi, benim güncellenmiş cevabı kontrol @Nima daha da yardımcı olun. –

1

Ben farklı bir yaklaşım öneriyoruz.

Özel Interceptor'lu özel bir OkHttp istemcisi uygulamanız gerekecektir. koduna bağlı olarak interceptor olarak

 OkHttpClient client = new OkHttpClient(); 
     client.interceptors().add(new MyInterceptor()); 
     mAdapter = new RestAdapter.Builder().setEndpoint(Consts.ENDPOINT).setClient(new OkClient(client)) 
       .setLogLevel(RestAdapter.LogLevel.BASIC).build(); 

normalde devam ya da bir istisna atabilir döndü.Böyle

şey:

public class MyInterceptor implements Interceptor { 

    @Override 
    public Response intercept(Chain chain) throws IOException { 
     Response response = chain.proceed(chain.request()); 

     if(response.code() == 0) { 
      throw new RuntimeException("Something went wrong!"); 
     } 

     return response; 
    } 
} 
+0

Bu umut verici bir çözüm gibi geliyor, ancak bununla ilgili büyük bir sorun var. 'okhttp' önleyicileri' http' düzeyinde çalışır ve response.code() tarafından verilen değer dönüşü aslında bir http kodudur, json'dan gelen kod değildir. Gerçek kodu ayıklamak için json'u ayrıştırmanız gerekir (ki bu kötü bir fikir çünkü daha sonra 'retrofit' dönüştürücüsü tarafından ayrıştırılacaktır). –

+0

@ VladimirMironov evet, bu http kodudur. Basit bir json gönderiyorsanız, sorunuzda olduğu gibi sadece 3 alanla, iki kez ayrıştırmak bir sorun olmamalıdır. Daha karmaşık bir şey varsa belki daha iyi bir çözüme ihtiyacınız olacak – LordRaydenMK

0

1 özel Observable.Operator:

public class YourOperator implements Observable.Operator{ 
    public void onNext(Data data){ 
     if (data.code != 0){ 
      //raise your custom Exception 
     } 
    } 
    public void onError(Throwable e){ 
     //handler Exception 
    } 
} 

2 kullanıcı gibi:

api.youRequest() 
    .lift(new YourOperator()) 
    .subscribe(....);