用 Kotlin 封裝一個 RxJava+Retrofit 網絡請求庫 HttpManger,包含多接口合併、文件下載

HttpManager

描述

這是一個封裝了Http網絡請求、HTTP多接口合併、網絡文件下載的庫。改編自wzgicemanRxRetrofit庫

Github地址:https://github.com/wkxjc/HttpManager

效果圖

        

下載

第一步. 在根目錄的build.gradle中添加以下代碼:

allprojects {
	repositories {
		...
		maven { url 'https://jitpack.io' }
	}
}

第二步. 添加gradle依賴

implementation 'com.github.wkxjc:HttpManager:1.7'

如何使用?

1.單個網絡請求:

private val httpManager by lazy { HttpManager(this) }
...
httpManager.request(randomWallpaperApi, object : HttpListener() {

    override fun onNext(result: String) {
        tvResult.text = result
    }
    
    override fun onError(error: Throwable) {
        tvResult.text = error.message
    }
})

2.多個網絡請求:

private val httpManager by lazy { HttpManager(this) }
...
httpManager.request(
    apis = arrayOf(randomWallpaperApi, categoryApi),
    listener = object : HttpListListener() {
        
        /**
         * 單個api結果回調
         */
        override fun onSingleNext(api: BaseApi, result: String): Any {
            when (api) {
                randomWallpaperApi -> {
                    Log.d("HttpListActivity", "收到單個結果:randomWallpaperApi:$result")
                    // 這裏可以將返回的字符串轉換爲任意對象,一般在這裏使用Gson/fastJson解析對象
                    return 123
                }
                categoryApi -> Log.d("HttpListActivity", "收到單個結果:categoryApi:$result")
            }
            return super.onSingleNext(api, result)
        }
        
        /**
         * 所有api結果回調
         */
        override fun onNext(resultMap: HashMap<BaseApi, Any>) {
            // 通過 as 方法,將resultMap中保存的對象取出並轉換成onSingleNext返回的類型
            tvResultList.text =
                "randomWallpaperApi result: ${resultMap[randomWallpaperApi] as Int}\n" +
                        "categoryApi result: ${resultMap[categoryApi].toString()}"
        }
        
        override fun onError(error: Throwable) {
            tvResultList.text = error.message
        }
    }
)

3.下載網絡文件:

HttpDownManager.down(DownConfig().apply {
    url = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
})

配置

使用HttpManager進行單個api請求或多個api請求之前,你需要一些準備工作.

第一步. 新建ApiConfig,繼承自DefaultApiConfig,重寫baseUrl變量:

class ApiConfig : DefaultApiConfig() {
    override var baseUrl = "你的網絡請求BaseUrl"
}

第二步. 在Application中初始化RxRetrofitApp,設置apiConfig:

RxRetrofitApp.apply {
    application = this@MyApplication
    apiConfig = ApiConfig()
}

第三步. 和使用Retrofit庫類似,新建ApiService,例如:

interface WallpaperApiService {

    @GET("v1/vertical/vertical")
    fun getRandomWallpaper(
        @Query("limit") limit: Int = 30,
        @Query("skip") skip: Int = 0,
        @Query("adult") adult: Boolean = false,
        @Query("first") first: Int = 0,
        @Query("order") order: String = "hot"
    ): Observable<String>
}

新建Api,繼承自BaseApi,例如:

class RandomWallpaperApi : BaseApi() {

    override fun getObservable(): Observable<String> {
        val apiService = retrofit.create(WallpaperApiService::class.java)
        return apiService.getRandomWallpaper()
    }
}

OK,這樣就能獲取到接口請求結果了。

使用HttpDownManager進行網絡文件下載之前,只需要確保在Application中初始化了RxRetrofitApp的application即可。

RxRetrofitApp.apply {
    application = this@MyApplication
}

返回結果統一解析

在實際開發中,後臺接口返回的數據一般是有統一格式的,例如本Demo中接口返回的數據統一格式如下:

class BaseResult {
    // 此變量爲0表示請求成功
    var code: Int = 0
    // 請求失敗時,此變量攜帶錯誤信息
    var msg: String = ""
    // 此變量存儲返回的業務數據
    var res: String = ""
}

在此框架中,我們可以將返回數據先統一按此結構解析,僅將返回的業務數據傳到業務層。新建ResultConverter:

class ResultConverter : IResultConverter {
    override fun convert(response: String): String {
        // 在這裏對結果統一解析
        val result = JSONObject.parseObject(response, BaseResult::class.java)
        // 通過定義的錯誤碼,統一做錯誤處理
        if (result.code != 0) throw Throwable("code != 0, msg = ${result.msg}")
        return result.res
    }
}

然後在Application中設置即可:

RxRetrofitApp.apply {
    ...
    resultConverter = ResultConverter()
}

在api中可以通過ignoreResultConverter配置關閉這一層解析

Http返回碼統一處理

有時候,後臺並不會通過BaseResult結構的errorMessage返回錯誤信息,而是通過Http請求的"404"或者"403"等等錯誤碼告知前端請求錯誤。
在此框架中,我們可以將Http返回碼統一處理。新建HttpResponseProcessor:

class HttpResponseProcessor : IHttpResponseProcessor {
    override fun handleResponse(response: Response): Response {
        // 在這裏可以處理http返回的錯誤碼:response.code(),這裏的錯誤碼不同於BaseResult中的errorCode
        if (response.code() >= 400) throw Throwable("Http response code = ${response.code()}")
        return response
    }
}

然後在Application中設置即可:

RxRetrofitApp.apply {
    ...
    httpResponseProcessor = HttpResponseProcessor()
}

定製

1.全局修改網絡請求默認配置

在ApiConfig中,不僅可以配置baseUrl,還可以配置以下參數,以下是默認值:

open class DefaultApiConfig {
    // Retrofit網絡請求的BaseUrl
    open var baseUrl = ""
    // 是否顯示Loading彈窗
    open var showLoading = true
    // Loading彈窗是否可取消
    open var loadingCancelable = true
    // 緩存配置
    open var cacheConfig = CacheConfig().apply {
        // 是否需要緩存處理
        cache = false
        // 有網的時候的緩存過期時間
        onlineCacheTime = 30
        // 沒網的時候的緩存過期時間
        offlineCacheTime = 60 * 60 * 24 * 30
    }
    // 是否忽略ResultConverter解析
    open var ignoreResultConverter: Boolean = false
    // 重試配置
    open var retry = RetryConfig().apply {
        // 重試次數
        count = 5
        // 重試延遲時間
        delay = 100L
        // 每次增加延遲的時間
        increaseDelay = 500L
    }
    // 超時時間配置
    open var timeOutConfig = TimeoutConfig().apply {
        // 連接超時時間
        connectionTime = 10L
        // 讀取超時時間
        readTime = 10L
        // 寫入超時時間
        writeTime = 10L
    }
    // Http請求head信息
    open var headers: Headers? = null
}

在這裏的配置是對所有的網絡請求生效的。

2.單個網絡請求修改默認配置

單個網絡請求可配置參數與全局網絡請求可配置參數相同。使用示例:

class RandomWallpaperApi : BaseApi() {

    init {
        // Retrofit網絡請求的BaseUrl
        baseUrl = "單獨配置baseUrl"
        // 是否顯示Loading彈窗
        showLoading = true
        // Loading彈窗是否可取消
        loadingCancelable = true
        // 緩存配置
        cacheConfig = CacheConfig().apply {
            // 是否需要緩存處理
            cache = false
            // 有網的時候的緩存過期時間
            onlineCacheTime = 30
            // 沒網的時候的緩存過期時間
            offlineCacheTime = 60 * 60 * 24 * 30
        }
        // 是否忽略ResultConverter解析
        ignoreResultConverter = false
        // 重試配置
        retry = RetryConfig().apply {
            // 重試次數
            count = 5
            // 重試延遲時間
            delay = 100L
            // 每次增加延遲的時間
            increaseDelay = 500L
        }
        // 超時時間配置
        timeOutConfig = TimeoutConfig().apply {
            // 連接超時時間
            connectionTime = 10L
            // 讀取超時時間
            readTime = 10L
            // 寫入超時時間
            writeTime = 10L
        }
        // Http請求head信息,示例如下:
        headers = Headers.of(mapOf("name1" to "value1", "name2" to "value2"))
    }
    
    override fun getObservable(): Observable<String> {
        val apiService = retrofit.create(WallpaperApiService::class.java)
        return apiService.getRandomWallpaper()
    }
}

3.Http多接口合併請求全局配置

Http多接口合併請求時,單個api配置的參數大多數仍然生效,只有showLoading、loadingCancelable兩個參數不再生效,需要單獨配置。
多接口合併可配置參數如下,以下是默認值:

open class DefaultHttpListConfig {
    // 是否顯示Loading彈窗
    open var showLoading: Boolean = true
    // Loading彈窗是否可取消
    open var loadingCancelable: Boolean = true
    // 是否按照順序請求api
    open var order: Boolean = false
}

如果需要全局修改Http多接口請求的配置,新建HttpListConfig類,繼承自DefaultHttpListConfig:

class HttpListConfig : DefaultHttpListConfig() {
    override var showLoading = true
    override var loadingCancelable = true
    override var order = false
}

然後在Application中設置即可:

RxRetrofitApp.apply {
    ...
    httpListConfig = HttpListConfig()
}

4.Http多接口合併請求單獨配置

單獨配置與全局配置的可配置參數相同。使用示例:

httpManager.request(
    apis = apis,
    config = HttpListConfig(showLoading = true, loadingCancelable = true, order = false),
    listener = listener
)

5.Http下載文件全局配置

下載文件時,全局默認配置如下:

open class DefaultDownConfig {
    /**保存的文件夾路徑,如果不設置,默認路徑是"應用緩存路徑/download/",如果設置爲外部路徑,需要自己確保有讀寫權限*/
    var saveDir: String = ""
        get() {
            if (field.isNotEmpty()) return field
            val cacheDir = RxRetrofitApp.application.externalCacheDir.absolutePath
                ?: throw Throwable("application is null")
            return "$cacheDir/download/"
        }
    /**下載進度更新頻率,即下載多少B之後更新一次,默認4K。使用[PROGRESS_BY_PERCENT]表示按百分比更新*/
    var progressStep = 1024 * 4
    /**重試配置*/
    var retry = RetryConfig()
    /**head信息*/
    var headers: Headers? = null
}

如果需要修改全局配置,新建DownConfig類,繼承自DefaultDownConfig類:

class DownConfig :DefaultDownConfig(){
    /**保存的文件夾路徑,如果不設置,默認路徑是"應用緩存路徑/download/",如果設置爲外部路徑,需要自己確保有讀寫權限*/
    override var saveDir: String = ""
        get() {
            if (field.isNotEmpty()) return field
            val cacheDir = RxRetrofitApp.application.externalCacheDir?.absolutePath
                ?: throw Throwable("application is null")
            return "$cacheDir/download/"
        }
    /**下載進度更新頻率,即下載多少B之後更新一次,默認4K。使用[PROGRESS_BY_PERCENT]表示按百分比更新*/
    override var progressStep = 1024 * 4
    /**重試配置*/
    override var retry = RetryConfig()
    /**head信息*/
    override var headers: Headers? = null
}

然後在Application中設置即可:

RxRetrofitApp.apply {
    ...
    downConfig = DownConfig()
}

6.Http下載文件單獨配置

單獨配置與全局配置的可配置參數相同。使用示例:

HttpDownManager.down(DownConfig().apply {
    url = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
    saveDir = "${RxRetrofitApp.application.externalCacheDir?.absolutePath}/download/"
    /**保存的文件名字,如果不設置,默認名字是url的最後一段*/
    saveFileName = "big_buck_bunny.mp4"
    /**下載進度更新頻率,即下載多少B之後更新一次,使用[PROGRESS_BY_PERCENT]表示按百分比更新*/
    /**進度更新頻率,下載多少Byte後更新一次進度。默認每下載4KB更新一次,使用[DownConfig.PROGRESS_BY_PERCENT]表示每下載百分之一更新一次*/
    progressStep = 1024 * 128
    /**重試配置*/
    retry = RetryConfig()
    /**head信息*/
    headers = Headers.of(mapOf("name1" to "value1", "name2" to "value2"))
})

Bug 反饋

如果您有任何反饋或建議,歡迎提交到 Github issues。或者給我留言、交流。

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