寫這個庫的目的是為了能夠讓程式碼看起來簡約,優雅。本庫是使用Kotlin實現的,所以它只支援Kotlin,同時整合了上傳,下載,斷點續傳,新增通用引數,和引數簽名等功能,節省開發時間。
github地址:github.com/VipMinF/Lyc…
本庫其他相關文章
框架引入
dependencies {
implementation 'com.vecharm:lycheehttp:1.0.2'
}
複製程式碼
如果你喜歡用RxJava 還需要加入
dependencies {
//RxJava
implementation 'com.vecharm.lycheehttp:lychee_rxjava:1.0.2'
//或者 RxJava2
implementation 'com.vecharm.lycheehttp:lychee_rxjava2:1.0.2'
}
複製程式碼
初始化
在Application中呼叫LycheeHttp::ini
,如果你不喜歡這種方式,自己寫個單例,呼叫時才初始化也是可以的,比較簡單我就不寫了。
override fun onCreate() {
super.onCreate()
LycheeHttp.init(MyCoreConfig(this))
}
複製程式碼
下載的API定義
下載只需要使用 Download
註解API就可以啦
@Download
@GET("https://xxxx/xxxx.apk")
fun download(): Call<DownloadBean>
複製程式碼
上傳的API定義
- 根據檔名稱的字尾名獲取,使用
Upload
進行註解
@Upload
@Multipart
@POST("http://xxx/xxx")
fun upload(@Part("file") file: File): Call<ResultBean<UploadResult>>
複製程式碼
- 對某個file進行註解,使用
FileType("png")
或者FileType("image/png")
@Multipart
@POST("http:/xxx/xxx")
fun upload(@Part("file") @FileType("png") file: File): Call<ResultBean<UploadResult>>
複製程式碼
- 對整個方法的所有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
,一般這種需求比較少。
使用
//普通請求
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定義可能不一樣,所以UploadTask
和DownloadTask
需要自己實現,下面是兩個例子(Rxjava2版的),也可以完全自己寫。
//上傳
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
來講。
- 如果要控制日誌的列印,可以
override DefaultCoreConfig::isShowLog
- 如果不喜歡Gson,可以
override DefaultCoreConfig::getGsonConverterFactory
- 如果要加入CookieJar,可以
override DefaultCoreConfig::getCookieJar
,可以試試PersistentCookieJar
- 如果不喜歡預設的
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()
}
}
複製程式碼
- 如果有新增通用引數和通用頭部的需求,可以
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
}
複製程式碼
- 上傳時,自動匹配的
MediaType
列表,放在DefaultMediaTypeManager
,目前裡面收集了300個左右,如果不夠用,可以繼承DefaultMediaTypeManager
在types
新增,或者override DefaultMediaTypeManager::filter
。 - 如果不喜歡預設的下載或上傳的進度的計算方式,可以實現
ISpeedComputer
,在初始化時替換ProgressHelper::downloadSpeedComputer
和ProgressHelper::uploadSpeedComputer
。
後話:第一次寫文章,寫的頭暈腦漲,寫的不太好。如果這篇文章對各位大大有用的話,可以給我點個贊鼓勵一下我哦,感謝!