Kotlin中Retrofit请求API无法打印MutableLiveData数据问题
问题描述
Kotlin开发初学者在Android开发学习过程中遇到以下问题:已在应用清单文件中添加网络权限,但调用API接口后无法打印任何返回数据,尝试输出MutableLiveData中承载的接口数据时未得到预期结果,相关实现代码如下:
ApiServices
interface ApiServices { @GET("/fixer/latest/") fun getRatesData( @Query("base") base: String, @Query("apikey") apikey: String ): Call<CurrencyModel> companion object { private const val url = "https://api.apilayer.com/" var apiServices: ApiServices? = null fun getInstance(): ApiServices { if (apiServices == null) { val retrofit = Retrofit.Builder() .baseUrl(url) .addConverterFactory(GsonConverterFactory.create()) .build() apiServices = retrofit.create(ApiServices::class.java) } return apiServices!! } } }
Repository
class CurrencyRepository constructor(private val apiServices: ApiServices) { fun getLatestRates() = apiServices.getRatesData("EUR", "API_KEY"); }
ViewModel
class CurrencyViewModel constructor(private val currencyRepository: CurrencyRepository) : ViewModel() { val currencyRatesList = MutableLiveData<CurrencyModel>() val errorMessage = MutableLiveData<String>() fun getLatestRates() { val response = currencyRepository.getLatestRates(); response.enqueue(object : retrofit2.Callback<CurrencyModel> { override fun onResponse( call: retrofit2.Call<CurrencyModel>, response: Response<CurrencyModel> ) { currencyRatesList.postValue(response.body()) } override fun onFailure(call: retrofit2.Call<CurrencyModel>, t: Throwable) { errorMessage.postValue(t.message) } }) } }
FactoryViewModel
class CurrencyViewModelFactory constructor(private val repository: CurrencyRepository) : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { return if (modelClass.isAssignableFrom(CurrencyViewModel::class.java)) { CurrencyViewModel(this.repository) as T }else{ throw IllegalArgumentException("Couldn't found ViewModel") } } }
MainActivity
class MainActivity : AppCompatActivity() { private val retrofitService = ApiServices.getInstance() lateinit var viewModel: CurrencyViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewModel = ViewModelProvider(this, CurrencyViewModelFactory(CurrencyRepository(retrofitService))) .get(CurrencyViewModel::class.java) viewModel.currencyRatesList.observe(this, Observer { Log.d(TAG, "onCreate: $it") }) viewModel.errorMessage.observe(this, Observer { viewModel.getLatestRates() }) } }
问题根因
- 核心逻辑遗漏:Activity中注册完LiveData观察者后,从未主动调用
viewModel.getLatestRates()触发接口请求。现有逻辑只有errorMessage收到错误回调时才会触发请求,应用首次启动时根本不会发起网络调用,自然不会有返回数据。 - 错误回调逻辑异常:
errorMessage的观察者中直接递归调用getLatestRates(),一旦请求触发错误会无限循环发起重试,直接导致请求队列阻塞。 - 响应校验缺失:Retrofit的
onResponse回调仅代表拿到了HTTP响应,不代表请求成功。现有逻辑未判断response.isSuccessful状态,也未处理响应体为null的情况,遇到4xx/5xx错误时不会走onFailure回调,会直接向LiveData投递null值。 - 路径写法不规范:
baseUrl已配置为带尾斜杠的根路径,@GET注解的路径开头额外加了/,后续如果调整baseUrl增加子路径,会出现路径拼接错误。
修复步骤
- 在MainActivity的
onCreate方法中,观察者注册完成后主动触发首次接口请求:
// 放在两个observe调用之后 viewModel.getLatestRates()
- 修正错误观察者逻辑,移除递归重试代码,先打印错误信息定位问题,重试逻辑建议绑定到手动点击事件上,不要自动递归调用:
viewModel.errorMessage.observe(this, Observer { errorMsg -> Log.e(TAG, "接口请求失败: $errorMsg") })
- 补全ViewModel中的响应状态校验,区分成功/失败响应:
override fun onResponse( call: retrofit2.Call<CurrencyModel>, response: Response<CurrencyModel> ) { if (response.isSuccessful && response.body() != null) { currencyRatesList.postValue(response.body()) } else { errorMessage.postValue("请求异常,状态码:${response.code()}") } }
- 修正ApiServices的接口路径,去掉
@GET路径开头的冗余斜杠:
@GET("fixer/latest/") fun getRatesData( @Query("base") base: String, @Query("apikey") apikey: String ): Call<CurrencyModel>
额外注意:代码中的
API_KEY需要替换为你在apilayer平台申请的真实有效密钥,否则会返回401权限错误。
内容的提问来源于stack exchange,提问作者asdwq
相关产品推荐
相关产品推荐

