Android - 使用泛型让1个RxJava改进调用使用相同的接口返回各种类型

时间:2017-11-12 22:57:09

标签: android kotlin rx-java retrofit2

我第一次玩Generics来清理一些重复编码的重复代码。

我能够制作一个通用的改装适配器,所以我的供应商不必每个都有一个独特的创造者,这真的很棒和令人兴奋。

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

现在我正在尝试进行通用网络通话,但我无法弄明白,并且想知道在改造是如何工作的情况下甚至是否可能?

我现在有5个服务,如下所示,所有服务都是不同的API。每个都有一个不同的端点,但都接受1个参数并返回它们的对象,这对于每个API调用略有不同。

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

所有响应对象都实现了一个接口来规范化响应数据,以便稍后显示

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

目前,我为每项服务进行了网络通话,如下所示

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

根据我对泛型的一点知识,似乎我应该能够传递一个通用服务并使用这个RxJava调用处理尽可能多的不同API端点?我不知道如何访问每个服务getCurrentTradingInfo方法,从我读到的,我怀疑是否可以使用改造接口?

如果可能的话,我不一定要寻找完整的答案(尽管解释会很好)但是我想知道在这个具体情况下是否甚至可以做到?如果不可能,我不想浪费时间。

2 个答案:

答案 0 :(得分:0)

所以我能够提出下面的内容比以前更好。我仍然无法找到一种解决方案,因此每个xxxRepository类中的每个API都有一些重复,但要少得多。

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

使用泛型的基类

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

答案 1 :(得分:0)

我建议使用compose()

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

然后就在你的displayOnTicker(Source)中(为Java主义道歉):

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

这允许你

  • 完全独立于类层次结构
  • 在其他位置重复使用相同的displayOnTicker
  • 也许把displayOnTicker放在mixin中?