【问题标题】:Struggle to get the same ViewModel instance努力获取相同的 ViewModel 实例
【发布时间】:2026-01-03 10:05:03
【问题描述】:

我不确定我是否正确理解 Android 中的 ViewModel 架构。我想 ViewModel 生命周期与活动相关,所以我们期待相同的实例,如果我们将活动或片段上下文传递给 ViewModelProvider 并不重要?

无论如何,这是我的 ViewModel:

class MainViewModel : ViewModel() {
    var teamName: String = "Warriors";
}

这是我的活动:

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)
        viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)

        viewModel.teamName = "Cavaliers";
        Log.d("YouQi", "activity viewModel.teamName: ${viewModel.teamName}");

        if (savedInstanceState == null) {
            supportFragmentManager.beginTransaction()
                    .replace(R.id.container, MainFragment.newInstance())
                    .commitNow()
        }
    }
}

最后这是我的片段:

class MainFragment : androidx.fragment.app.Fragment() {
    companion object {
        fun newInstance() = MainFragment()
    }

    private lateinit var viewModel: MainViewModel

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        return inflater.inflate(R.layout.main_fragment, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
        Log.d("YouQi", "fragment viewModel.teamName: ${viewModel.teamName}");
    }

}

我在 Logcat 中得到以下输出:

2018-06-03 16:06:24.591 31124-31124/com.axzae.zapkotlin D/YouQi: activity viewModel.teamName: Cavaliers
2018-06-03 16:06:24.652 31124-31124/com.axzae.zapkotlin D/YouQi: fragment viewModel.teamName: Warriors

它显示价值没有更新到骑士队。我是不是用错了 ViewModel 应该用 Dagger 来实现单例?

【问题讨论】:

  • 我就像你刚开始学习android架构组件一样,我注意到在示例中它们通常使用活动的上下文(github.com/googlesamples/android-architecture/blob/…,看看onCreateViewgithub.com/googlesamples/android-architecture/blob/…obtainViewModel
  • 另一方面,您的代码确实看起来像您想要不同的视图模型 - 一个用于活动,一个用于片段,因为您请求它们的方式(否则请求视图模型用于活动似乎是逻辑仅在这两种情况下)。无论如何,让我们等待有更多经验的人澄清。

标签: android kotlin android-viewmodel


【解决方案1】:

您使用的是什么ViewModelProvider 很重要 - 来自活动或片段。片段请尝试使用ViewModelProviders.of(getActivity())

这实际上非常方便 - 您可以分别保留片段相关模型和更通用的活动绑定模型。

【讨论】:

  • 谢谢!我之前在片段中避免使用activity 上下文的原因是因为 kotlin 抱怨活动可能是一个空对象。我必须将其定义为viewModel = ViewModelProviders.of(activity!!).get(MainViewModel::class.java)。这是预期的吗?
  • 是的...你可以使用requireActivity()方法返回Not-null,如果你在不适当的时候使用它会崩溃
【解决方案2】:

不,您不需要使用依赖注入来实现 ViewModel 中的单例。您可以像这样将活动上下文传递给 ViewModel:

viewModel = ViewModelProviders.of(activity).get(MainViewModel::class.java)// by this you will get the same value of teamName as your activity

【讨论】: