努力获得相同的ViewModel实例

4

我不确定我是否正确理解了Android中的ViewModel架构。我认为ViewModel的生命周期与Activity相关,因此我们期望获得相同的实例,无论是将Activity或Fragment上下文传递给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()
        }
    }
}

最后,这是我的Fragment:
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架构组件,我注意到在示例中通常使用活动的上下文(https://github.com/googlesamples/android-architecture/blob/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksFragment.java,请查看`onCreateView`和https://github.com/googlesamples/android-architecture/blob/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksActivity.java,`obtainViewModel`)。 - Fyodor Volchyok
另一方面,您的代码确实看起来像是您想要不同的视图模型 - 一个用于活动,一个用于片段,因为您请求它们的方式(否则,在这两种情况下仅请求活动的视图模型似乎是合理的)。无论如何,让我们等待有更多经验的人来澄清。 - Fyodor Volchyok
2个回答

5

你使用的 ViewModelProvider 来自活动还是来自片段确实很重要。请尝试在片段中使用 ViewModelProviders.of(getActivity())

这非常方便 - 你可以将与片段相关的模型和更一般的活动绑定模型分开管理。


谢谢!我之前在片段中避免使用“activity”上下文的原因是因为Kotlin会抱怨活动可能是一个空对象。我必须将其定义为“viewModel = ViewModelProviders.of(activity!!).get(MainViewModel::class.java)”才行。这是否符合预期? - You Qi
1
是的...你可以使用requireActivity()方法,它返回非空值,或者在不适当的时刻使用它会导致崩溃。 - kzotin

4
不需要使用依赖注入来实现ViewModel中的单例。您可以像这样将活动上下文传递给ViewModel:
viewModel = ViewModelProviders.of(activity).get(MainViewModel::class.java)// by this you will get the same value of teamName as your activity

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接