写这个库的目的是为了能够让代码看起来简约,优雅。本库是使用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。
后话:第一次写文章,写的头晕脑涨,写的不太好。如果这篇文章对各位大大有用的话,可以给我点个赞鼓励一下我哦,感谢!