Android MVVM模式下Retrofit调用API返回值为空问题求助
问题分析与解决方案
你的问题核心在于LiveData实例被替换导致Observer失效,再加上异步API请求的时机问题,才让你看不到预期的状态码。我们一步步来解决:
问题根源
- LiveData实例被替换:你的ViewModel里,
test最初指向testInput这个LiveData对象,但调用clicked()时,你把test重新赋值为createCode()返回的新LiveData。而Activity里的Observer是绑定在最初的testInput实例上的,新的LiveData变化根本不会被监听。 - 异步请求的时机错误:你在
clicked()里直接打印test.value,这时候API请求还在后台执行,回调还没触发,test.value自然是空的。
修正方案(现代MVVM+Coroutines写法)
我们用Coroutines替代回调,同时保证LiveData实例不被替换,遵循单向数据流的原则:
1. 改造Retrofit接口为挂起函数
Retrofit从2.6.0开始支持挂起函数,这比回调更简洁易维护:
interface MyAPIInterface { @POST("your-api-endpoint") // 替换成你的实际接口路径 suspend fun createCode(@Body sendUser: CreateCodeUserClass): Response<Void> }
2. 重构Repository层
用挂起函数处理API请求,统一封装成功和失败的逻辑:
class APIRepository { // 初始化你的Retrofit接口实例 private val myApiInterface: MyAPIInterface = Retrofit.Builder() .baseUrl("your-base-url") .addConverterFactory(GsonConverterFactory.create()) .build() .create(MyAPIInterface::class.java) suspend fun createCode(): Int { return try { val sendUser = CreateCodeUserClass().apply { username = "09360767928" } val response = myApiInterface.createCode(sendUser) response.code() // 返回接口成功状态码 } catch (t: Throwable) { 10000 // 请求失败时返回自定义错误码 } } }
3. 修正ViewModel
保持单一LiveData实例,用viewModelScope处理协程(自动在ViewModel销毁时取消任务,彻底避免内存泄漏):
class TestViewModel: ViewModel() { // 内部用MutableLiveData更新值,对外暴露不可变的LiveData,保证数据单向流动 private val _test = MutableLiveData<Int>(1) val test: LiveData<Int> = _test private val repository = APIRepository() fun clicked(){ // 启动协程执行异步API请求 viewModelScope.launch { val code = repository.createCode() _test.value = code // 协程会自动切回主线程,直接更新LiveData即可 } } }
4. 修正MainActivity
注意用最新的ViewModelProvider(旧的ViewModelProviders已经过时):
class MainActivity : AppCompatActivity() { private lateinit var viewModel: TestViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewModel = ViewModelProvider(this)[TestViewModel::class.java] viewModel.test.observe(this) { data -> println(data.toString()) textView.text = data.toString() } button.setOnClickListener { viewModel.clicked() } } }
为什么这样改?
- 单一LiveData实例:始终用同一个
_test来更新值,Observer能持续监听变化,不会因为实例替换而失效。 - Coroutines替代回调:代码更简洁易读,避免回调嵌套,同时
viewModelScope自动管理协程生命周期,不会造成内存泄漏。 - 单向数据流:对外暴露不可变的
LiveData,只有ViewModel能更新数据,符合MVVM的架构原则,保证数据流向清晰。
内容的提问来源于stack exchange,提问作者Dayyan Nili Sani
相关产品推荐
相关产品推荐

