一、使用背景
网络请求在App开发中是不可避免的开发功能点,Android自带的ottp用于网络请求,于是便衍生了各种便捷的网络请求三方库。
个人经常会使用到Retrofit来进行网络请求,因为会经常用到此框架,所以对此进行一次二次封装。
retrofit的网络请求的工作本质上是OKHttp完成,而 Retrofit 仅负责 网络请求接口的封装。
App应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求参数、Header、Url 等信息,之后由 OkHttp 完成后续的请求操作
在服务端返回数据之后,OkHttp 将原始的结果交给 Retrofit,Retrofit根据用户的需求对结果进行解析
关于它的基本使用:可参考下面的博客
Carson带你学Android:这是一份详细的 Retrofit使用教程(含实例讲解)_android retrofit-CSDN博客
二、封装思路
1.设计返回数据实体类
2.retrofit实例化及其基本封装
3.请求回调的设计
4.网路请求的方法封装
5.具体实现
三、具体实现
1.实体类
@Keep
data class BaseResponseBody(var code:Int,var msg:String?="",var result:JsonElement?=null,var successful:Boolean,var toast:String?=""
)
code:一般是和后端约定的返回码,常见的例如200(请求成功);
msg:请求信息;
successful:是否成功;
result:接口返回数据;(之前用过Any,但是后端返回的数据格式有时候会不一样,有可能是Boolean,String,或者就是个列表,并不是一个json,所以后面我换成了JsonElement)
2.retrofit实例化及其基本封装
enum class RetrofitManager {INSTANCE;var retrofit: Retrofit? = nullget() {if (field == null) {field = getRetrofitObject()//获取实例}return field}private setprivate fun getRetrofitObject(): Retrofit {val loggingInterceptor = HttpLoggingInterceptor { message -> //打印retrofit日志LogUtils.i("RetrofitLog", "retrofitBack = $message")}loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)//设置打印等级val client = OkHttpClient.Builder().addInterceptor(loggingInterceptor).addInterceptor(HeaderInterceptor())//添加拦截器.connectTimeout(20, TimeUnit.SECONDS)//连接超时事件.readTimeout(20, TimeUnit.SECONDS).writeTimeout(20, TimeUnit.SECONDS).build()return Retrofit.Builder().baseUrl(BASE_URL).client(client).addConverterFactory(GsonConverterFactory.create()).build()//配置属性}companion object {private const val BASE_URL = "https://api.test.com/"//baseurl}
}class HeaderInterceptor : Interceptor {@Throws(IOException::class)override fun intercept(chain: Interceptor.Chain): Response {val originalRequest: Request = chain.request()val langAndCountry = "${Locale.getDefault().language}-${Locale.getDefault().country}"val newRequestBuilder =originalRequest.newBuilder().header("deviceId", DeviceUtils.getUniqueDeviceId(true) ?: DeviceUtils.androidID).header("appId", "26").header("lang", langAndCountry)//语言.header("loginPlatform", "APP").header("platform", "1").header("version", AppNormalUtils.getVersionName() ?:AppConstant.APP_VERSION_NAME )if (AppConstant.getIsLogin() && AppConstant.getToken().isNotEmpty()) {newRequestBuilder.header("token", AppConstant.getToken())//用户token}val newRequest = newRequestBuilder.build()return chain.proceed(newRequest)}
}
1.RetrofitManager类主要是生成一个retrofit实例并对其进行基本属性的配置。
2.HttpLoggingInterceptor是日志拦截器,他会打印网络请求的各种日志,此类需要在build.gradle引入依赖
implementation com.squareup.okhttp3:logging-interceptor:3.4.1
3.HeaderInterceptor 主要是配置请求header,根据和后端的约定,进行配置
3.请求回调的设计
请求回调代码实现:最重要的肯定是onSuccess和onError方法,onSuccess回调返回数据,onError返回报错和错误类型
abstract class RetrofitCallback {fun onStart() {}fun onCompleted() {}abstract fun onSuccess(responseBody: BaseResponseBody)abstract fun onError(t: Throwable?, type: Int? = 0)fun serverErrMsg() {}fun reqErrMsg() {}}
4.网路请求的方法封装
1.定义一个接口
主要实现了GET,POST和图片上传三类接口
import java.util.List;
import java.util.Map;import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.http.PartMap;
import retrofit2.http.QueryMap;
import retrofit2.http.Url;public interface Request {@GET()Call<BaseResponseBody> get(@Url String url);@GET()Call<BaseResponseBody> get(@Url String url, @QueryMap Map<String, Object> map);@POST()Call<BaseResponseBody> post(@Url String url);@POST()Call<BaseResponseBody> post(@Url String url, @Body Map<String, Object> map);@POSTCall<BaseResponseBody> post(@Url String url, @Body List<Object> body);@Multipart@POST()Call<BaseResponseBody> uploadImage(@Url String url,@Part MultipartBody.Part image,@PartMap Map<String, RequestBody> map // 使用 @PartMap 替代 @Body);
}
2.具体网络请求方法类
import android.content.Intent
import androidx.lifecycle.ViewModelProvider
import com.uz.cashloanuzi.R
import okhttp3.MultipartBody
import okhttp3.RequestBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Responseclass RetrofitUtil {companion object {fun get(url: String?, callback: RetrofitCallback, isShowToast: Boolean = true) {sendRequest(request[url], callback, isShowToast)}fun get(url: String?,map: Map<String?, Any?>?,callback: RetrofitCallback,isShowToast: Boolean = true) {sendRequest(request[url, map], callback, isShowToast)}fun post(url: String?, callback: RetrofitCallback) {sendRequest(request.post(url), callback)}fun post(url: String?,map: Map<String?, Any?>?,callback: RetrofitCallback,isShowToast: Boolean = true) {sendRequest(request.post(url, map), callback, isShowToast)}fun post(url: String?, list: List<Any?>, callback: RetrofitCallback, isShowToast: Boolean = true) {sendRequest(request.post(url, list), callback, isShowToast)}fun uploadImage(url: String?,image: MultipartBody.Part,map: Map<String, RequestBody>,callback: RetrofitCallback) {sendRequest(request.uploadImage(url, image, map), callback)}private val request: Requestget() {val retrofit = RetrofitManager.INSTANCE.retrofitreturn retrofit!!.create(Request::class.java)}private fun sendRequest(call: Call<BaseResponseBody>,callback: RetrofitCallback,showToast: Boolean = true//是否展示toast) {callback.onStart()call.enqueue(object : Callback<BaseResponseBody?> {//enqueue异步请求override fun onResponse(call: Call<BaseResponseBody?>,response: Response<BaseResponseBody?>) {callback.onCompleted()if (response.isSuccessful) {try {val responseBody: BaseResponseBody? = response.body()if (responseBody == null) callback.onError(null, type = AppConstant.REQUEST_ERROR_DATA)else if (responseBody.code == 200) {callback.onSuccess(responseBody)} else if (responseBody.code == 401) {toLogin()//与后端定义的特殊返回code} else {if (responseBody.toast?.isNotEmpty() == true && showToast) {makeText(responseBody.toast!!)} else if (responseBody.msg?.isNotEmpty() == true && showToast) {makeText(responseBody.msg!!)}callback.onError(null, type = AppConstant.REQUEST_ERROR_DATA)}} catch (e: Exception) {e.printStackTrace()}} else {callback.onError(null, type = AppConstant.REQUEST_ERROR_NET)callback.serverErrMsg()}}override fun onFailure(call: Call<BaseResponseBody?>, t: Throwable) {if (showToast) ToastUtils.makeTextShort(BaseApplication.getInstance().applicationContext.getString(R.string.net_request_error_tips))callback.onCompleted()callback.onError(t, type = AppConstant.REQUEST_ERROR_NET)callback.reqErrMsg()}})}fun toLogin() {}}
}
代码有百来行,但是很简单,我就没加注释
5.具体实现
private fun getAppNeedUpdateInfo() {RetrofitUtil.get(AppApi.APP_VERSION_CONTROL, object : RetrofitCallback() {override fun onSuccess(responseBody: BaseResponseBody) {val gson =Gson()val data = gson.fromJson(responseBody.result,UpdateBean::class.java)......}}override fun onError(t: Throwable?, type: Int?) {}})}object AppApi {const val APP_VERSION_CONTROL="/appVersion/needUpdateForce"
.....
}
如果需要带参数:
val map = HashMap<String, Int>()// HashMap<String, Int>,也可以是 HashMap<String, Any>,根据接口要求自己进行设置map["applicationId"] = applicationId!!map["user"] = user!!val url = "/application/$applicationId/test-info"RetrofitUtil.get(url, map.toMap(), object : RetrofitCallback() {override fun onSuccess(responseBody: BaseResponseBody) {}override fun onError(t: Throwable?, type: Int?) {}})
图片上传
val map: MutableMap<String, RequestBody> = HashMap(16)val typeValue = if (curImageType == 0) "POSITIVE" else "OPPOSITE"map["type"] = RequestBody.create("text/plain".toMediaTypeOrNull(), typeValue)//参数map["cardType "] = RequestBody.create("text/plain".toMediaTypeOrNull(), "ID_CARD")//参数val requestFile = RequestBody.create("image/jpeg".toMediaTypeOrNull(), file)val part = MultipartBody.Part.createFormData("file", file.name, requestFile)//"file"这个参数名记得和后端对其RetrofitUtil.uploadImage(AppApi.UPLOAD_IMAGE, part, map, object : RetrofitCallback() {override fun onSuccess(responseBody: BaseResponseBody) {}override fun onError(t: Throwable?, type: Int?) {}})
之前也封装过retrofit,大同小异,我这就不展开记录了。