1、前言
之前在学习郭霖《第一行代码》时按部就班地写过一个彩云天气 App,对里面的网络请求框架的封装印象非常深刻,很喜欢这种 Retrofit
+ Kotlin
+ 协程的搭配使用。随后也在自己的项目里参考了这部分的代码。但随着代码的深入编写和功能的复杂,原来的框架已经无法满足我的使用了。原主要有如下的痛点:
- 缺少失败的回调
- 显示加载中动画比较麻烦
后面我自己试着努力去封装一个简单易用的框架,可惜个人能力有限,自己封装的框架总是不如人意。好在还有很多优秀的博客和代码可供参考。在此基础上,对彩云天气 App中的网络请求框架做了一些修改,尽可能地做到简单易用。以请求玩安卓的登录接口为例(用户名和密码是我自己申请的,见代码),页面上有一个按钮,点击按钮后就发起登录请求。
先来看看发起请求后的回调怎么写:
viewModel.loginLiveData.observeState(this) {
onStart {
LoadingDialog.show(activity)
Log.d(TAG, "请求开始")
}
onSuccess {
Log.d(TAG, "请求成功")
showToast("登录成功")
binding.tvResult.text = it.toString()
}
onEmpty {
showToast("数据为空")
}
onFailure {
Log.d(TAG, "请求失败")
showToast(it.errorMsg.orEmpty())
binding.tvResult.text = it.toString()
}
onFinish {
LoadingDialog.dismiss(activity)
Log.d(TAG, "请求结束")
}
}
回调一共有五种,会在下文详细介绍。这里采用了DSL
的写法,如果你喜欢传统的写法,可以调用另外一个扩展方法observeResponse()
,由于它最后一个参数就是请求成功的回调,所以借助 Lambda 表达式的特性,可以简洁地写成如下的形式:
viewModel.loginLiveData.observeResponse(this){
binding.tvResult.text = it.toString()
}
如果还需要其他回调,可以使用具名参数加上,如下所示:
viewModel.loginLiveData.observeResponse(this, onStart = {
LoadingDialog.show(this)
}, onFinish = {
LoadingDialog.dismiss(activity)
}) {
binding.tvResult.text = it.toString()
}
2、框架搭建
开始之前必须说明,这个框架是基于《第一行代码》(第三版)中的彩云天气 App的,它的架构图如下所示,如果你阅读过《第一行代码》或者谷歌的相关文档,那么想必对此不会陌生。
2.1 添加依赖库
//简化在 Activity 中声明 ViewModel 的代码
implementation "androidx.activity:activity-ktx:1.3.1"
// lifecycle
def lifecycle_version = "2.3.1"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
// retrofit2
def retrofit_version = "2.9.0"
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
// okhttp
def okhttp_version = "4.8.1"
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
//日志拦截器
implementation('com.github.ihsanbal:LoggingInterceptor:3.1.0') {
exclude group: 'org.json', module: 'json'
}
2.2 Retrofit
构建器
Retrofit
构建器这里做了分层,基类做了一些基本的配置,子类继承后可以添加新的配置,并配置自己喜欢的日志拦截器。
private const val TIME_OUT_LENGTH = 8L
private const val BASE_URL = "https://www.wanandroid.com/"
abstract class BaseRetrofitBuilder {
private val okHttpClient: OkHttpClient by lazy {
val builder = OkHttpClient.Builder()
.callTimeout(TIME_OUT_LENGTH, TimeUnit.SECONDS)
.connectTimeout(TIME_OUT_LENGTH, TimeUnit.SECONDS)
.readTimeout(TIME_OUT_LENGTH, TimeUnit.SECONDS)