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

Android:按官方文档在ViewModel中使用by lazy是否合理?

在ViewModel中使用by lazy初始化LiveData是否合理?

Android官方文档给出的ViewModel示例代码如下:

class MyViewModel : ViewModel() {
  private val users: MutableLiveData<List<User>> by lazy {
    MutableLiveData<List<User>>().also {
        loadUsers()
    }
  }

  fun getUsers(): LiveData<List<User>> {
    return users
  }

  private fun loadUsers() {
    // 执行异步操作获取用户数据
  }
}

我对在ViewModel中用by lazy初始化LiveData的写法存疑,因为接触的项目里都没这么写过。比如如果把loadUsers()改成下面这样:

private fun loadUsers() {
    // 执行异步操作获取用户数据
    users.value = ...
}

这时候调用loadUsers()会再次访问users变量,而它还没完成初始化,就会导致loadUsers()被重复调用——比如在Activity或Fragment中观察这个LiveData时,就会触发这个问题。


问题根源分析

这段官方示例的写法存在明显的初始化循环依赖问题:

  • 当第一次访问users时,lazy块会创建MutableLiveData实例,紧接着调用loadUsers()
  • 而修改后的loadUsers()又去访问users.value,此时lazy块还没执行完(users变量还没完成赋值),就会再次触发lazy初始化逻辑,导致loadUsers()被递归调用,最终可能引发栈溢出或者重复发起异步请求的问题。

为什么官方会这么写?

官方示例里的loadUsers()只是占位逻辑,没有访问users变量,所以不会触发循环。但这种写法很容易误导开发者,实际项目中几乎不会这么用——因为只要loadUsers()需要更新users的值,就必然会踩坑。

更合理的实现方式

实际项目中,更稳妥的写法是提前初始化LiveData,再单独触发数据加载逻辑,避免循环依赖:

class MyViewModel : ViewModel() {
  private val users = MutableLiveData<List<User>>()

  init {
    loadUsers()
  }

  fun getUsers(): LiveData<List<User>> {
    return users
  }

  private fun loadUsers() {
    // 执行异步操作获取用户数据
    users.value = ...
  }
}

或者如果需要懒加载(比如只有当UI观察数据时才加载),可以通过标记位实现安全的懒加载:

class MyViewModel : ViewModel() {
  private val users = MutableLiveData<List<User>>()
  private var isLoaded = false

  fun getUsers(): LiveData<List<User>> {
    if (!isLoaded) {
      loadUsers()
      isLoaded = true
    }
    return users
  }

  private fun loadUsers() {
    // 执行异步操作获取用户数据
    users.value = ...
  }
}

总结

  • 官方示例的写法仅适用于loadUsers()不依赖users变量的场景,实际项目中几乎没有实用价值
  • by lazy + 在初始化块中调用会修改自身的方法,本质是错误的写法,会引发循环初始化问题
  • 优先选择提前初始化LiveData并在init块加载数据,或者通过标记位实现安全的懒加载

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 07:03:17