基於Retrofit2實現的LycheeHttp

寫這個庫的目的是爲了可以讓代碼看起來簡約,優雅。本庫是使用Kotlin實現的,因此它只支持Kotlin,同時集成了上傳,下載,斷點續傳,添加通用參數,和參數簽名等功能,節省開發時間。java

github地址:github.com/VipMinF/Lyc…git

本庫其餘相關文章github

框架引入

dependencies {
    implementation 'com.vecharm:lycheehttp:1.0.2'
}
複製代碼

若是你喜歡用RxJava 還須要加入json

dependencies {
     //RxJava
     implementation 'com.vecharm.lycheehttp:lychee_rxjava:1.0.2'
    //或者 RxJava2
     implementation 'com.vecharm.lycheehttp:lychee_rxjava2:1.0.2'
}
複製代碼

初始化

在Application中調用LycheeHttp::ini,若是你不喜歡這種方式,本身寫個單例,調用時才初始化也是能夠的,比較簡單我就不寫了。api

override fun onCreate() {
        super.onCreate()
        LycheeHttp.init(MyCoreConfig(this))
    }
複製代碼

下載的API定義

下載只須要使用 Download 註解API就能夠啦服務器

@Download
    @GET("https://xxxx/xxxx.apk")
    fun download(): Call<DownloadBean>
複製代碼

上傳的API定義

  1. 根據文件名稱的後綴名獲取,使用Upload 進行註解
@Upload
    @Multipart
    @POST("http://xxx/xxx")
    fun upload(@Part("file") file: File): Call<ResultBean<UploadResult>>
複製代碼
  1. 對某個file進行註解,使用FileType("png") 或者FileType("image/png")
@Multipart
    @POST("http:/xxx/xxx")
    fun upload(@Part("file") @FileType("png") file: File): Call<ResultBean<UploadResult>>
複製代碼
  1. 對整個方法的全部file參數進行註解,使用MultiFileType("png")或者MultiFileType("image/png")
@Multipart
    @MultiFileType("png")
    @POST("http://xxx/xxx")
    fun upload(@PartMap map: MutableMap<String, Any>): Call<ResultBean<UploadResult>>
複製代碼

API的定義和原來沒有什麼區別,只是多了幾個註解,上傳不再用RequestBody做爲參數了。若是要打印文件的內容,可使用FileLog,通常這種需求比較少。app

使用

//普通請求
      getService<API>().hello().request {
          onSuccess = { Toast.makeText(App.app, it.data ?: "", Toast.LENGTH_SHORT).show() }
          onErrorMessage = {}
          onCompleted = {}
      }

      //單個文件下載
      getService<API>().download().request(File(App.app.externalCacheDir, "xx.apk")) {
          onSuccess = { Toast.makeText(App.app, "${it.downloadInfo?.fileName} 下載完成", Toast.LENGTH_SHORT).show() }
          onErrorMessage = {}
          onCompleted = {}
      }
        
      //多任務下載
      addDownloadTaskButton.setOnClickListener {
          val downloadTask = DownloadTask()
          val file = File(App.app.externalCacheDir, "qq${adapter.data.size + 1}.apk"
          downloadTask.download("https://xxx/xxx.apk", file)
          adapter.addData(downloadTask)
      }
        
      //多任務上傳
      addUploadTaskButton.setOnClickListener {
          val uploadTask = UploadTask()
          uploadTask.upload(File(App.app.externalCacheDir, "qq${adapter.data.size + 1}.apk"))
          adapter.addData(uploadTask)
      }
        
複製代碼

三個註解能夠同時使用,優先級FileType > MultiFileType > Upload,喜歡哪種就看你本身了框架

注意

對於多任務上傳和下載,因爲每一個業務的API定義可能不同,因此UploadTaskDownloadTask須要本身實現,下面是兩個例子(Rxjava2版的),也能夠徹底本身寫。dom

//上傳
class UploadTask : DefaultTask() {
    override fun onCancel() {}
    override fun onResume(url: String, filePath: String) {}
    
    fun upload(file: File) {
        getService<API>().upload(file).upload {
            onUpdateProgress = onUpdate
            onSuccess = { Toast.makeText(App.app, "${id}上傳完成", Toast.LENGTH_LONG).show() }
        }
    }
}
//下載
class DownloadTask : DefaultTask() {

    override fun onCancel() {
        service?.dispose()
    }

    override fun onResume(url: String, filePath: String) {
        download(url, File(filePath))
    }

    var service: Disposable? = null

    fun download(url: String, saveFile: File) {
        setPathInfo(url, saveFile.absolutePath)

        service = getService<API>().download(url, range.bytesRange()).request(saveFile.setRange(range)) {
            onUpdateProgress = onUpdate
            onSuccess = { Toast.makeText(App.app, "${id}下載完成", Toast.LENGTH_LONG).show() }
        }
    }
}
複製代碼

另外注意若是你傾向於使用RxJava,別忘了添加RxJavaCallAdapterFactory或者你的自定義的實現

class RxJavaConfig(val context: Application) : DefaultCoreConfig() {
    ......
    override fun onInitRetrofit(builder: Retrofit.Builder): Retrofit.Builder {
        builder.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        return super.onInitRetrofit(builder)
    }
}
複製代碼

最簡配置

class SimplestConfig:DefaultCoreConfig() {
    override fun getHostString() = "https://host:port/"
}
複製代碼

其餘配置

若是你不喜歡默認的配置,能夠實現ICoreConfig接口本身寫一個,下面的我都是基於默認配置Defaultxxxx來說。ide

  1. 若是要控制日誌的打印,能夠override DefaultCoreConfig::isShowLog
  2. 若是不喜歡Gson,能夠override DefaultCoreConfig::getGsonConverterFactory
  3. 若是要加入CookieJar,能夠override DefaultCoreConfig::getCookieJar,能夠試試PersistentCookieJar
  4. 若是不喜歡默認的ResponseBean 或者說項目比較複雜,一些接口返回ResultBean,一些接口返回OKBean,那麼能夠實現IResponseHandler接口。並在api執行以前調用DefaultCoreConfig:registerResponseHandler
class SimplestConfig : DefaultCoreConfig() {
    init {
        /* * 註冊自定義的返回值處理,能夠註冊多個 * */
        registerResponseHandler(ResponseBean::class.java, MyResponseHandler::class.java)
    }
    .......
}
class MyResponseHandler : DefaultResponseHandler() {

    override fun onError(status: Int, message: String?) {
        if (10001 == status) {//沒有登錄
            Toast.makeText(App.app, "沒有登錄", Toast.LENGTH_LONG).show()
        }
        super.onError(status, message)
        Toast.makeText(App.app, "$status:$message", Toast.LENGTH_LONG).show()
    }
}
複製代碼
  1. 若是有添加通用參數和通用頭部的需求,能夠override DefaultCoreConfig::getRequestConfig,而後繼承DefaultRequestConfig,下面是例子。
class MyRequestConfig : DefaultRequestConfig() {

    /** * 添加默認頭部參數 * */
    override fun addHeaders(newRequestBuild: Request.Builder, oldRequest: Request) {
        newRequestBuild.addHeader("Accept", "application/json")
        newRequestBuild.addHeader("Accept-Language", "zh")
    }
    
    /** * 添加通用參數 * */
    override fun onAddCommonParams(map: MutableMap<String, String>) {
        map["app_version"] = com.vecharm.lychee.sample.BuildConfig.VERSION_CODE.toString()
        map["nonce"] = map["nonce"] ?: randomUUID()
        map["timestamp"] = System.currentTimeMillis().div(1000).toString()
        map["pkg_name"] = App.app.packageName
        map["app_sign"] = "s9fkjs0a-d234ew-adfadf"
    }
    
    /** * 參數簽名 * */
    override fun onSignParams(map: MutableMap<String, String>) {
        super.onSignParams(map)
        //簽完名將key移除,避免將這個傳到服務器
        map.remove("app_sign")
    }
    
    /** * 不須要參與簽名的字段,文件參與簽名默認是進行md5 * */
    override fun unSignParamNames() = arrayOf("file")

    /** * 是否參數簽名 * */
    override fun isSignParam() = true
}
複製代碼
  1. 上傳時,自動匹配的MediaType列表,放在DefaultMediaTypeManager,目前裏面收集了300個左右,若是不夠用,能夠繼承DefaultMediaTypeManagertypes添加,或者override DefaultMediaTypeManager::filter
  2. 若是不喜歡默認的下載或上傳的進度的計算方式,能夠實現ISpeedComputer,在初始化時替換ProgressHelper::downloadSpeedComputerProgressHelper::uploadSpeedComputer

後話:第一次寫文章,寫的頭暈腦漲,寫的不太好。若是這篇文章對各位大大有用的話,能夠給我點個贊鼓勵一下我哦,感謝!

相關文章
相關標籤/搜索