Android: uso de generics para tener 1 llamada de actualización de RxJava que devuelve varios types usando la misma interfaz

Estoy jugando con Generics por primera vez para limpiar algunos códigos repetidos que tengo sobre las llamadas de actualización.

Pude hacer un adaptador de actualización genérico, por lo que mis proveedores no tenían que tener un creador único, lo que fue realmente increíble y emocionante.

private fun <T> create(service: Class<T>, baseUrl: String): T { val retrofit = Retrofit.Builder() .client(client) .addConverterFactory(MoshiConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .baseUrl(baseUrl) .build() return retrofit.create(service) } 

Ahora estoy tratando de hacer una llamada de networking genérica, pero no soy capaz de resolverlo, y me pregunto si es posible teniendo en count cómo funciona Retrofit.

Tengo 5 services como los de abajo en este momento, todos golpeando diferentes API. Cada uno tiene un punto final diferente, pero todos aceptan 1 parámetro y devuelven su object que es ligeramente diferente para cada llamada API.

 interface ServiceA { @GET("v2/ticker") fun getCurrentTradingInfo(@Query("book") orderBook: String): Observable<CurrentTradingInfo> } 

Todos los objects de respuesta implementan una interfaz para normalizar los datos de respuesta para que pueda mostrarlos más tarde


 data class CurrentTradingInfo(val mid: String, val bid: String, val ask: String, val last_price: String, val low: String, val high: String, val volume: String, val timestamp: String) : normalizedData { override fun lastPrice(): String { return last_price } override fun timeStamp(): String { return timestamp } } 

Actualmente, tengo una llamada de networking para cada service como a continuación

  val disposable = service.getCurrentTradingInfo(ticker.ticker) .observeOn(AndroidSchedulers.mainThread()) .repeatWhen { result -> result.delay(10, TimeUnit.SECONDS) } .retryWhen { error -> error.delay(10, TimeUnit.SECONDS) } .subscribeOn(Schedulers.io()) .subscribe({ result -> val tradingInfo = TradingInfo(result.lastPrice(), result.timeStamp()) networkDataUpdate.updateData(ticker, tradingInfo) callback.updateUi(ticker) }, { error -> error.printStackTrace() }) 

Desde mi poco conocimiento de los generics, parece que debería poder pasar un service genérico y manejar tantos puntos de API diferentes usando esta llamada de RxJava. Sin embargo, no sé cómo acceder a cada método getCurrentTradingInfo de services, y por lo que leo, ¿no estoy seguro si es posible usar interfaces de actualización?

No necesariamente estoy buscando una respuesta completa si es posible (aunque una explicación sería agradable) pero me pregunto si es posible hacerlo en este escenario específico. No quiero seguir perdiendo el time si ni siquiera es posible.

Así que pude encontrar el siguiente, que es mucho mejor de lo que tenía antes. Todavía no puedo encontrar una forma de evitar la interfaz, por lo que hay una pequeña duplicación para cada API en cada class de xxxRepository pero mucho less.

 interface QuadrigaService { @GET("v2/ticker") fun getCurrentTradingInfo(@Query("book") query: String): Observable<CurrentTradingInfo> } 

 class QuadrigaRepository(private val service: QuadrigaService) : BaseExchangeRepository() { override fun feedType(): String { return CryptoPairs.QUADRIGA_BTC_CAD.exchange } override fun startFeed(tickers: List<CryptoPairs>, presenterCallback: NetworkCompletionCallback, networkDataUpdate: NetworkDataUpdate) { clearDisposables() tickers.forEach { ticker -> startFeed(service.getCurrentTradingInfo(ticker.ticker), ticker, presenterCallback, networkDataUpdate) } } } 

Y la class base usando generics


 abstract class BaseExchangeRepository : Exchange { var disposables: CompositeDisposable = CompositeDisposable() fun clearDisposables() { if (disposables.size() != 0) { disposables.clear() } } fun <T> startFeed(observable: Observable<T>, ticker: CryptoPairs, presenterCallback: NetworkCompletionCallback, networkDataUpdate: NetworkDataUpdate) { val disposable = observable.observeOn(AndroidSchedulers.mainThread()) .repeatWhen { result -> result.delay(10, TimeUnit.SECONDS) } .subscribeOn(Schedulers.io()) .subscribe({ result -> result as NormalizedTickerData Log.d("Result", ticker.toString() + "last price is ${result.lastPrice()}") val tradingInfo = TradingInfo(result.lastPrice(), result.timeStamp()) networkDataUpdate.updateData(ticker, tradingInfo) presenterCallback.updateUi(ticker) }, { error -> error.printStackTrace() }) disposables.add(disposable) } override fun stopFeed() { disposables.clear() } } 

Sugeriría usar compose() :

  val disposable = service.getCurrentTradingInfo(ticker.ticker) .compose(displayOnTicker(ticker)) .subscribe(); 

Luego solo en su displayOnTicker(Source) (disculpas por los Java-ismos):

  return source -> source .observeOn(AndroidSchedulers.mainThread()) .repeatWhen { result -> result.delay(10, TimeUnit.SECONDS) } .retryWhen { error -> error.delay(10, TimeUnit.SECONDS) } .subscribeOn(Schedulers.io()) .doOnNext({ result -> val tradingInfo = TradingInfo(result.lastPrice(), result.timeStamp()) networkDataUpdate.updateData(ticker, tradingInfo) callback.updateUi(ticker) }) // add .doOnError / .onErrorResumeNext as desinetworking ; 

Esto te permite

  • ser completamente independiente de una jerarquía de classs
  • reutilizar el mismo displayOnTicker en otra location
  • tal vez coloque el displayOnTicker en un mixin?
  • RXJava ... emiten un observable cada segundo
  • Cómo pasar nulo a un Observable con tipo anulable en RxJava 2 y Kotlin
  • RxJava Debounce onNext ()
  • ¿Hay alguna manera de cambiar mi método a la stream Observable que será una cadena de modificadores?
  • Aplicando transformación a cada elemento en Single <List <T >>
  • Fusionar datos de diferentes Observables y elegir diferentes estrategias de búsqueda, según la disponibilidad de datos
  • RXJava Ignorar error y continuar en cadena
  • ¿Cuándo no usar el Observable de RxJava?
  • Método comodín de Kotlin
  • Mockito querido pero no invocado
  • Invoque RxJava2 cancelable / desechable del hilo correcto