Kotlin中Retrofit回调优化、回调移除及单例改造问题
问题解答
1. 回调的自动移除与手动取消
- 自动移除:Retrofit在请求完成(
onResponse或onFailure执行后),会自动释放对Callback对象的引用,不会持续持有。但如果Callback内部持有Activity/Fragment等外部类的强引用,且请求未完成时外部类被销毁,会引发内存泄漏。 - 手动移除(取消请求):需要保留
Call实例并调用cancel()方法。可以修改工具类让UserAction返回Call对象,供调用方在需要时取消:
调用时取消请求:// 修改工具类的UserAction方法 fun UserAction(action:String, userData: UserData, toUserData: UserData?=null, returnCallback:(ReturnMessage)->Unit): Call<ReturnMessage> { val callAuth = restApiUser.authOraddUser(action, userData.username, userData.phonenumber, toUserData?.username) callAuth.enqueue(object : Callback<ReturnMessage> { // 原有回调逻辑不变 }) return callAuth }
若需批量取消,可在单例类中维护一个请求集合,统一管理:val call = RetrofitInstance.UserAction("retrieveChatForUser",cuserData){ ... } // 需要取消时执行 call.cancel()object RetrofitInstance { private val activeCalls = mutableSetOf<Call<*>>() fun UserAction(...): Call<ReturnMessage> { val callAuth = restApiUser.authOraddUser(...) activeCalls.add(callAuth) callAuth.enqueue(object : Callback<ReturnMessage> { override fun onResponse(call: Call<ReturnMessage>, response: Response<ReturnMessage>) { activeCalls.remove(call) // 原有逻辑 } override fun onFailure(call: Call<ReturnMessage>, t: Throwable) { activeCalls.remove(call) // 原有逻辑 } }) return callAuth } fun cancelAllActiveCalls() { activeCalls.forEach { it.cancel() } activeCalls.clear() } }
2. 改造为单例模式
使用Kotlin的object关键字实现单例,同时提前初始化Retrofit和Service实例(避免每次调用重复创建,提升性能):
object RetrofitInstance { // 懒加载Retrofit实例,全局复用 private val retrofit by lazy { Retrofit.Builder() .baseUrl(CommonVals.base_url) .addConverterFactory(GsonConverterFactory.create()) .build() } // 懒加载Service实例 private val restApiUser by lazy { retrofit.create(RestApiUser::class.java) } fun UserAction(action:String, userData: UserData, toUserData: UserData?=null, returnCallback:(ReturnMessage)->Unit): Call<ReturnMessage> { val callAuth = restApiUser.authOraddUser(action, userData.username, userData.phonenumber, toUserData?.username) callAuth.enqueue(object : Callback<ReturnMessage> { override fun onResponse(call: Call<ReturnMessage>, response: Response<ReturnMessage>) { if (response.isSuccessful) { val post = response.body() post?.let { Log.d("api","${action} ${it}") returnCallback(it) } } else { Log.d("apierror", "${action} error ${response.code()}") } } override fun onFailure(call: Call<ReturnMessage>, t: Throwable) { Log.d("apierror","${action} error ${t.message}") } }) return callAuth } private interface RestApiUser { @FormUrlEncoded @POST("{action}") fun authOraddUser( @Path("action") action:String, @Field("username") username: String?=null, @Field("password") password: String?=null, @Field("username2") username2: String?=null, ): Call<ReturnMessage> } }
调用方式简化为:
RetrofitInstance.UserAction("retrieveChatForUser",cuserData){ returnMessage-> if(returnMessage.status==true) { val chatList = returnMessage.content as List<Any> adapter.setData(chatList) } }
3. 优化带回调的Retrofit使用
3.1 统一错误处理逻辑
目前仅打印错误日志,未通知调用方。可定义密封类封装请求结果,让回调能处理成功/失败场景:
// 定义结果密封类 sealed class ApiResult<out T> { data class Success<out T>(val data: T) : ApiResult<T>() data class Error(val message: String, val code: Int? = null) : ApiResult<Nothing>() } // 修改UserAction的回调类型 fun UserAction(action:String, userData: UserData, toUserData: UserData?=null, returnCallback:(ApiResult<ReturnMessage>)->Unit): Call<ReturnMessage> { val callAuth = restApiUser.authOraddUser(action, userData.username, userData.phonenumber, toUserData?.username) callAuth.enqueue(object : Callback<ReturnMessage> { override fun onResponse(call: Call<ReturnMessage>, response: Response<ReturnMessage>) { if (response.isSuccessful) { val post = response.body() post?.let { Log.d("api","${action} ${it}") returnCallback(ApiResult.Success(it)) } ?: returnCallback(ApiResult.Error("返回数据为空")) } else { val errorMsg = "请求失败,状态码:${response.code()}" Log.d("apierror", "${action} ${errorMsg}") returnCallback(ApiResult.Error(errorMsg, response.code())) } } override fun onFailure(call: Call<ReturnMessage>, t: Throwable) { val errorMsg = t.message ?: "网络请求失败" Log.d("apierror","${action} ${errorMsg}") returnCallback(ApiResult.Error(errorMsg)) } }) return callAuth }
调用时统一处理结果:
RetrofitInstance.UserAction("retrieveChatForUser",cuserData){ result-> when(result) { is ApiResult.Success -> { val returnMessage = result.data if(returnMessage.status==true) { val chatList = returnMessage.content as List<Any> adapter.setData(chatList) } } is ApiResult.Error -> { // 处理错误,比如弹出提示 } } }
3.2 避免内存泄漏
若回调持有Activity/Fragment等对象,建议使用弱引用:
// 在Activity中 val weakAdapter = WeakReference(adapter) RetrofitInstance.UserAction("retrieveChatForUser",cuserData){ result-> when(result) { is ApiResult.Success -> { val returnMessage = result.data if(returnMessage.status==true) { val chatList = returnMessage.content as List<Any> weakAdapter.get()?.setData(chatList) } } is ApiResult.Error -> { // 错误处理 } } }
3.3 可选:切换到协程替代回调
Kotlin协程比回调更简洁,且更易管理生命周期。改造步骤:
- 修改Service为挂起函数:
private interface RestApiUser { @FormUrlEncoded @POST("{action}") suspend fun authOraddUser( @Path("action") action:String, @Field("username") username: String?=null, @Field("password") password: String?=null, @Field("username2") username2: String?=null, ): ReturnMessage } - 改造UserAction为挂起函数:
suspend fun UserAction(action:String, userData: UserData, toUserData: UserData?=null): ApiResult<ReturnMessage> { return try { val response = restApiUser.authOraddUser(action, userData.username, userData.phonenumber, toUserData?.username) ApiResult.Success(response) } catch (e: Exception) { ApiResult.Error(e.message ?: "请求失败") } } - 调用时使用协程作用域:
lifecycleScope.launch { val result = RetrofitInstance.UserAction("retrieveChatForUser",cuserData) when(result) { is ApiResult.Success -> { // 处理成功逻辑 } is ApiResult.Error -> { // 处理错误逻辑 } } }
内容的提问来源于stack exchange,提问作者Lingam mohan krishnasen
相关产品推荐
相关产品推荐

