You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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协程比回调更简洁,且更易管理生命周期。改造步骤:

  1. 修改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
    }
    
  2. 改造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 ?: "请求失败")
        }
    }
    
  3. 调用时使用协程作用域:
    lifecycleScope.launch {
        val result = RetrofitInstance.UserAction("retrieveChatForUser",cuserData)
        when(result) {
            is ApiResult.Success -> {
                // 处理成功逻辑
            }
            is ApiResult.Error -> {
                // 处理错误逻辑
            }
        }
    }
    

内容的提问来源于stack exchange,提问作者Lingam mohan krishnasen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 21:05:04