一、封装步骤
直接上代码:
首先引入相关依赖:
api 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation("com.squareup.okhttp3:okhttp:4.10.0")
api 'com.github.JessYanCoding:RetrofitUrlManager:v1.4.0'
api 'com.google.code.gson:gson:2.10.1'
- 新建一个单例的RetrofitClient简单封装
package com.kim.jetpackmvi.network
import android.util.Log.INFO
import com.kim.jetpackmvi.network.logging.Level
import com.kim.jetpackmvi.network.logging.LoggingInterceptor
import me.jessyan.retrofiturlmanager.RetrofitUrlManager
import okhttp3.ConnectionPool
import okhttp3.OkHttpClient
import org.greenrobot.eventbus.android.BuildConfig
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
/**
* @ClassName: RetrofitClient
* @Description: Retrofit Kotlin 封装
* @Author: kim
* @Date: 2/18/23 5:53 PM
*/class RetrofitClient {
companion object {
val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
RetrofitClient()
}
}
private lateinit var retrofit: Retrofit
private lateinit var okHttpClient: OkHttpClient
private constructor() {
//禁用缓存
// if (httpCacheDirectory == null) {
// httpCacheDirectory = File(mContext.getCacheDir(), "goldze_cache")
// }
// try {
// if (cache == null) {
// cache = Cache(httpCacheDirectory, CACHE_TIMEOUT)
// }
// } catch (e: Exception) {
// KLog.e("Could not create http cache", e)
// }
val sslParams: HttpsUtils.SSLParams = HttpsUtils.getSslSocketFactory()
okHttpClient = RetrofitUrlManager.getInstance().with(OkHttpClient.Builder())
//.cookieJar(CookieJarImpl(PersistentCookieStore(mContext))) // .cache(cache)
//.addInterceptor(BaseInterceptor(headers)) //.addInterceptor(CacheInterceptor(mContext)) .sslSocketFactory(sslParams.sSLSocketFactory!!, sslParams.trustManager!!)
.addInterceptor(
LoggingInterceptor.Builder() //构建者模式
.loggable(true/*BuildConfig.DEBUG*/) //是否开启日志打印
.setLevel(Level.BASIC) //打印的等级
.log(INFO) // 打印类型
.request("Request") // request的Tag
.response("Response") // Response的Tag
//.addHeader("log-header", "I am the log request header.") // 添加打印头, 注意 key 和 value 都不能是中文 .build()
)
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.connectionPool(
ConnectionPool(
8,
15,
TimeUnit.SECONDS
)
) // 这里你可以根据自己的机型设置同时连接的个数和时间,我这里8个,和每个保持时间为10s
.build()
// retrofit = Retrofit.Builder()
// .client(okHttpClient)
// .addConverterFactory(GsonConverterFactory.create())
// //.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
// .baseUrl(url)
// .build()
}
/**
* create you ApiService * Create an implementation of the API endpoints defined by the `service` interface. */
fun <T> create(url: String, service: Class<T>?): T {
if (service == null) {
throw RuntimeException("Api service is null!")
}
retrofit = Retrofit.Builder()
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
//.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(url)
.build()
return retrofit.create(service)
}
}
在以上代码中,结合了日志拦截器等自定义的拦截器(会单独写文章列出,与本文无关),可以使用create
创建Retrofit对象。
- 建立一个文件,名为ApiCall,有如下内容:
package com.kim.jetpackmvi.network
import android.util.Log
import com.google.gson.JsonParseException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.apache.http.conn.ConnectTimeoutException
import org.json.JSONException
import retrofit2.HttpException
import java.io.IOException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
/**
* @ClassName: ApiCall
* @Description: java类作用描述
* @Author: kim
* @Date: 2/19/23 12:38 AM
*/suspend inline fun <T> apiCall(crossinline call: suspend CoroutineScope.() -> T, crossinline onSuccess: ((T) -> Unit), crossinline onError: ((Exception) -> Unit)) {
withContext(Dispatchers.IO) {
var res: T? = null
try {
res = call()
onSuccess(res)
} catch (e: Throwable) {
Log.e("ApiCaller", "request error", e)
// 请求出错
onError(ApiException.build(e))
}
}
}
// 网络、数据解析错误处理
class ApiException(val code: Int, override val message: String?, override val cause: Throwable? = null)
: RuntimeException(message, cause) {
companion object {
// 网络状态码
const val CODE_NET_ERROR = 4000
const val CODE_TIMEOUT = 4080
const val CODE_JSON_PARSE_ERROR = 4010
const val CODE_SERVER_ERROR = 5000
// 业务状态码
const val CODE_AUTH_INVALID = 401
fun build(e: Throwable): ApiException {
return if (e is HttpException) {
ApiException(CODE_NET_ERROR, "网络异常(${e.code()},${e.message()})")
} else if (e is UnknownHostException) {
ApiException(CODE_NET_ERROR, "网络连接失败,请检查后再试")
} else if (e is ConnectTimeoutException || e is SocketTimeoutException) {
ApiException(CODE_TIMEOUT, "请求超时,请稍后再试")
} else if (e is IOException) {
ApiException(CODE_NET_ERROR, "网络异常(${e.message})")
} else if (e is JsonParseException || e is JSONException) {
// Json解析失败
ApiException(CODE_JSON_PARSE_ERROR, "数据解析错误,请稍后再试")
} else {
ApiException(CODE_SERVER_ERROR, "系统错误(${e.message})")
}
}
}
}
- 建立一个Service
/**
* @ClassName: TestApiService
* @Description: java类作用描述
* @Author: kim
* @Date: 2/18/23 5:50 PM
*/interface TestApiService {
/**
* 测试post接口,发给他啥它返回啥 */
@Headers(DOMAIN_NAME+ DOMAIN_NAME_postTest)
@POST("post")
// 注意这里的suspend
suspend fun postTest(@Body json: String): ResponseBody
}
lateinit var apiService: TestApiService
- 调用
//使用retrofit url manager初始化
private fun initRetrofit() {
apiService = RetrofitClient.instance.create(
testUrl,
TestApiService::class.java
)
//RetrofitClient.getInstance().apiService = apiService;
RetrofitUrlManager.getInstance().putDomain(DOMAIN_NAME_postTest, testUrl)
RetrofitUrlManager.getInstance().setGlobalDomain(testUrl)
}
//在view model中调用协程
viewModelScope.launch {
delay(2000)
apiCall({
apiService.postTest("{\"aaa\":123}")
}, {
Logger.i(it.string())
}, {
Logger.i(it.message + "")
})
}
结束。
二、简单解释
Retrofit已经支持Kotlin的协程了,在Api Service中加入suspend关键字即可。
使用ApiCall函数传入三个参数,要运行的协程、成功回调、返回回调。
直接在withContext(Dispatchers.IO)
中使用即可。
参考链接
Retrofit+协程,网络请求封装实战 – 知乎 (zhihu.com) 优雅的封装网络请求,协程 + Retrofit – 掘金 (juejin.cn)
参考了1的状态回调,参考了2的协程封装
近期评论