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

Retrofit的onResponse回调中无法给成员变量mData赋值如何解决

问题根因

你遇到的问题本质是异步请求的时序问题:

  • call.enqueue()是异步方法,发起网络请求后会立刻返回,不会阻塞当前线程,loadData方法不会等待onResponse/onFailure回调执行,就会先走return mData.toString()的逻辑,此时mData还没被赋值,自然返回的是null。
  • 等后续网络请求完成,onResponse里的mData = 20才会执行,但此时loadData早就返回结果了,所以你感知不到赋值生效。

解决方法

方案1:使用接口回调传递结果

这是Java/Kotlin开发里最常用的传统方案,自定义回调接口,等异步请求完成后把结果回传给调用方:
首先定义回调接口:

interface WeatherLoadCallback {
    fun onSuccess(data: Int, temp: String)
    fun onFailure(errorMsg: String?)
}

然后改造loadData方法,去掉返回值,传入回调参数:

class ApiConnect {
    private val BASE_URL = "https://www.metaweather.com"
    // 不需要提前定义mData存储结果,直接通过回调传递即可
    fun loadData(woeidID: String, callback: WeatherLoadCallback) {
        val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        val service = retrofit.create(WeatherApi::class.java)
        val call = service.queryWeather(woeidID)
        call.enqueue(object : Callback<Example> {
            override fun onResponse(call: Call<Example>, response: Response<Example>) {
                if (response.isSuccessful) {
                    response.body()?.let {
                        val detay = it.consolidatedWeather
                        val cevap = detay!![0].theTemp.toString()
                        Log.i("woeid", "iç: $cevap")
                        // 回调返回结果
                        callback.onSuccess(20, cevap)
                        return@let
                    }
                    callback.onFailure("响应体为空")
                } else {
                    callback.onFailure("请求失败,错误码:${response.code()}")
                }
            }

            override fun onFailure(call: Call<Example>, t: Throwable) {
                Log.i("response", "onFailure: " + t.message)
                callback.onFailure(t.message)
            }
        })
    }
}

调用示例:

ApiConnect().loadData("你的woeid", object : WeatherLoadCallback {
    override fun onSuccess(data: Int, temp: String) {
        // 此处拿到结果,更新UI或者做后续处理
        Log.i("result", "data: $data, temp: $temp")
    }

    override fun onFailure(errorMsg: String?) {
        // 处理错误逻辑
    }
})

方案2:使用Kotlin协程(Kotlin环境推荐使用)

如果你的项目已经接入Kotlin协程,可以直接将回调式API转为挂起函数,代码更简洁:
首先给WeatherApi里的queryWeather方法加上suspend修饰符,去掉Call包装:

interface WeatherApi {
    @GET("你的接口路径")
    suspend fun queryWeather(@Path("woeid") woeidID: String): Example
}

改造loadData为挂起函数:

class ApiConnect {
    private val BASE_URL = "https://www.metaweather.com"
    private val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    private val service = retrofit.create(WeatherApi::class.java)

    suspend fun loadData(woeidID: String): Result<Pair<Int, String>> {
        return try {
            val response = service.queryWeather(woeidID)
            val detay = response.consolidatedWeather
            val cevap = detay!![0].theTemp.toString()
            Result.success(20 to cevap)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
}

调用示例(在ViewModel里用viewModelScope,或者Activity里用lifecycleScope):

lifecycleScope.launch {
    val result = ApiConnect().loadData("你的woeid")
    result.onSuccess { (data, temp) ->
        Log.i("result", "data: $data, temp: $temp")
    }.onFailure {
        Log.e("result", "请求失败", it)
    }
}

方案3:阻塞等待请求结果(不推荐,会阻塞线程,禁止在主线程使用)

如果你非要同步获取结果,可以用call.execute()方法,但是必须放在子线程执行,否则会触发主线程网络请求报错:

fun loadData(woeidID: String): String {
    val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    val service = retrofit.create(WeatherApi::class.java)
    val call = service.queryWeather(woeidID)
    // 同步执行,阻塞当前线程
    val response = call.execute()
    return if (response.isSuccessful) {
        response.body()?.let {
            val detay = it.consolidatedWeather
            detay!![0].theTemp.toString()
            20.toString()
        } ?: "null"
    } else {
        "null"
    }
}

注意:该方案会阻塞线程,只适合特殊场景使用,日常开发优先选方案1或方案2。

内容的提问来源于stack exchange,提问作者ERTUGRUL KOC

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 16:06:03