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?
  • Realm Turn Transaction en observable
  • Tipo de devolución diferente en RxJava 2 (actualización desde RxJava1)
  • RxAndroid - Manejar errores con el operador Zip
  • Cómo get el último valor emitido de observable
  • Cómo usar la class ContextWrapper con subscribeWith
  • Para una function de Kotlin utilizada como expresión, ¿hay una forma concisa de operar y devolver un valor?
  • Pausa / Reanudar un timer / retraso en RX
  • OnComplete nunca se llamó con toSortedList () y groupBy ()
  • Escuchar posts y escribir commands en un flujo observable
  • RxJava Debounce onNext ()
  • Cómo get el valor emitido desde el primer observable