You need to enable JavaScript to run this app. Android开发:Activity无法观察ViewModel内LiveData的状态变更
优惠活动
大模型
产品
解决方案
定价
更多

Android开发:Activity无法观察ViewModel内LiveData的状态变更

问题现象
  • 作为Android开发新手,在宿主Activity中观察关联ViewModel内的Boolean类型LiveData状态时,应用启动阶段能正常收到数据的初始值,后续所有状态变更(比如切换Fragment时改动的数值)都无法触发已设置的观察者。
  • 预期目标:通过MyMusicViewOn这个MutableLiveData的状态变化,对应监听ViewModel初始化、ViewModel清理、界面切换的时机。

现有实现代码

自定义ViewModel

class MyMusicViewModel : ViewModel() {
    private var _MyMusicViewOn = MutableLiveData<Boolean>()
    val MyMusicViewOn: LiveData<Boolean> get() = _MyMusicViewOn

    init {
        Timber.i("MyMusicViewModel Init Called!")
        setMyMusicView(true)
    }

    override fun onCleared() {
        super.onCleared()
        Timber.i("MyMusicViewModel Cleared!")
        setMyMusicView(false)
    }

    fun setMyMusicView(setter: Boolean) {
        Timber.i("MyMusicViewModel setter called! %s", setter)
        _MyMusicViewOn.value = setter
    }
}

宿主Activity代码

class FullscreenActivity : AppCompatActivity() {
    private val viewModel: MyMusicViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewModel.MyMusicViewOn.observe(this, Observer { MyMusicViewOn ->
            Timber.i("Observer called for MyMusicViewOn %s", MyMusicViewOn)
        })
    }
}

关联Fragment代码

class MyMusicFragment : Fragment() {
    private lateinit var viewModel: MyMusicViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val binding = DataBindingUtil.inflate<FragmentMyMusicBinding>(
            inflater,
            R.layout.fragment_my_music,
            container,
            false
        )
        // 错误的ViewModel获取逻辑
        viewModel = ViewModelProvider(this).get(MyMusicViewModel::class.java)
        return binding.root
    }

    override fun onResume() {
        super.onResume()
        Timber.i("MyMusicViewFragment resumed!")
        viewModel.setMyMusicView(true)
    }
}

问题根因

  • 问题出在Fragment获取ViewModel的传参上:代码里写的ViewModelProvider(this)传入的this是Fragment自身,这会让系统从Fragment独有的ViewModelStore存储空间里获取(或新建)一个MyMusicViewModel实例,和宿主Activity里通过by viewModels()从Activity的ViewModelStore里拿到的ViewModel根本不是同一个对象。
  • 两个独立的ViewModel实例各持有独立的_MyMusicViewOn LiveData对象,Fragment修改自己持有实例的LiveData值时,Activity观察的是自己手里那个ViewModel的LiveData,两边数据完全不互通,自然无法触发Activity里设置的观察者回调。

修复方案

如果要实现Activity和Fragment共享同一个ViewModel实例,Fragment获取ViewModel时需要把绑定源指定为宿主Activity,两种常用写法:

  • 使用activityViewModels属性代理,直接绑定和Activity相同的ViewModel实例:
    private val viewModel: MyMusicViewModel by activityViewModels()
    
  • 手动创建ViewModelProvider时传入宿主Activity作为绑定源,注意不要传Fragment自己:
    // 传入requireActivity()而非Fragment本身的this
    viewModel = ViewModelProvider(requireActivity()).get(MyMusicViewModel::class.java)
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.02 16:06:04