Kotlin使用關鍵字reified優化Retrofit2

 問題場景:

retrofit大家都很熟悉.創建使用大概如下.

(1) 定義接口請求類

interface RetrofitService {
    @GET("/posts")
    fun getPosts(): Deferred<Response<List<Post>>>
}

(2)創建接口實體類

object RetrofitFactory {
    const val BASE_URL = "https://jsonplaceholder.typicode.com"

    fun createRetrofitService(): RetrofitService = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(CoroutineCallAdapterFactory())
        .client(getClient())
        .build()
        .create(RetrofitService::class.java)

    private fun getClient(): OkHttpClient =
        OkHttpClient.Builder().addInterceptor(LoggerInterceptor()).build()
}

(3)調用

object NetRepository {

    private val service: RetrofitService by lazy {
        RetrofitFactory.createRetrofitService()
    }

    fun getDeferredPost() = service.getPosts()

}

現在我現在我的應用裏面對接的網絡接口只有一種類型就是RetrofitService,假設這個Service是專門處理商品類型的網絡請求.如果

這時候需求變更,需要在添加用戶登錄,支付等接口功能該如何設計代碼呢?

方案一

BASE_URL是沒變麼,直接在RetrofitService接口類寫完剩下的接口不就完事兒了.

分析:

這樣是可以.但是不滿足java設計模式的單一職責你的接口有關於支付的,有關於的用戶信息的,又有關於支付相關的.這樣代碼不清爽.好你說可以忍受反正自己挖的坑自己含着淚也得填.如果連域名都變了,該怎麼辦?

方案二

那我創建多個接口對象就好了

object RetrofitFactory {
    const val BASE_URL = "https://jsonplaceholder.typicode.com"

    const val BASE_URL1 = "https://jsonplaceholder.typicode.com1"

    fun createRetrofitService(url: String): RetrofitService =
        createRetrofit(BASE_URL).create(RetrofitService::class.java)


    fun createRetrofitService1(url: String): RetrofitService1 =
        createRetrofit(BASE_URL1).create(RetrofitService1::class.java)


    private fun createRetrofit(url: String): Retrofit = Retrofit.Builder()
        .baseUrl(url)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(CoroutineCallAdapterFactory())
        .client(getClient())
        .build()

    private fun getClient(): OkHttpClient =
        OkHttpClient.Builder().addInterceptor(LoggerInterceptor()).build()
}

分析:

確實解決了方案1的痛點,但是2個寫起來看起來還不費事,試試看10個,20個..這樣代碼裏面充滿了大量類似的代碼.我們是不是可以合併同類項目呢?

方案三

這邊很有人就想起來泛型,但是在java裏面有泛型擦除,但是到了kotlin我們就可以解決了這個問題.koltin裏面有個保留關鍵子reified翻譯成中文是具體化.它的作用就是這個是爲了滿足inline特性而設計的語法糖,因爲給函數使用內聯之後,編譯器會用其函數體來替換掉函數調用,而如果該函數裏面有泛型就可能會出現編譯器不懂該泛型的問題,所以引入reified,使該泛型被智能替換成對應的類型.

object RetrofitFactory {
    const val BASE_URL = "https://jsonplaceholder.typicode.com"

    const val BASE_URL1 = "https://jsonplaceholder.typicode.com1"

    inline fun <reified T> createRetrofitService(url: String): T =
        createRetrofit(url).create(getRetrofitService<T>())


    fun createRetrofit(url: String): Retrofit = Retrofit.Builder()
        .baseUrl(url)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(CoroutineCallAdapterFactory())
        .client(getClient())
        .build()

    inline fun <reified T> getRetrofitService(): Class<T> = T::class.java


    private fun getClient(): OkHttpClient =
        OkHttpClient.Builder().addInterceptor(LoggerInterceptor()).build()
}

調用類

object NetRepository {

    private val service: RetrofitService by lazy {
        RetrofitFactory.createRetrofitService<RetrofitService>(RetrofitFactory.BASE_URL)
    }

    private val service1: RetrofitService1 by lazy {
        RetrofitFactory.createRetrofitService<RetrofitService1>(RetrofitFactory.BASE_URL1)
    }

    fun getPost() {
        service.getPosts()
    }

    fun getPost1() {
        service1.getPosts()
    }
}

分析:

通過泛型T直接獲得具體類RetrofitService,RetrofitService1.這樣以後增加接口,只要寫接口類,域名url,其他代碼都可以保持不變.減少了後期維護的工作量.代碼請見https://github.com/ThinkJarvis/Mvvm/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章