我应该如何使用ViewModel在两个片段?



我有一个具有一个活动和两个片段的应用程序,在第一个片段中,我应该能够将数据插入数据库,在第二个片段中,我应该能够在recyclerView中看到添加的项目。

所以我已经做了数据库,我的回收视图适配器,和ViewModel,

现在的问题是我应该如何管理这一切?

我应该在活动中初始化ViewModel并以某种方式从片段调用它来使用插入吗?

我应该在两个片段中初始化视图模型两次吗?

我的代码是这样的:

让我们假设我在我的Activity中初始化viewholder:

class MainActivity : AppCompatActivity() {
private val articoliViewModel: ArticoliViewModel by viewModels {
ArticoliViewModelFactory((application as ArticoliApplication).repository)
}
}

然后我的FirstFragments方法,我应该使用viewModel将数据添加到数据库中,看起来像这样:

class FirstFragment : Fragment() {
private val articoliViewModel: ArticoliViewModel by activityViewModels()
private fun addArticolo(barcode: String, qta: Int) { // function which add should add items on click
// here i should be able to do something like this
articoliViewModel.insert(Articolo(barcode, qta))
}
}

和我的SecondFragment

class SecondFragment : Fragment() {    
private lateinit var recyclerView: RecyclerView
private val articoliViewModel: ArticoliViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView = view.findViewById(R.id.recyclerView)
val adapter = ArticoliListAdapter()
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(activity)
// HERE I SHOULD BE ABLE DO THIS   
articoliViewModel.allWords.observe(viewLifecycleOwner) { articolo->
articolo.let { adapter.submitList(it) }
}
} 
}

编辑:

我的ViewModel看起来像这样:

class ArticoliViewModel(private val repository: ArticoliRepository): ViewModel() {
val articoli: LiveData<List<Articolo>> = repository.articoli.asLiveData()
fun insert(articolo: Articolo) = viewModelScope.launch {
repository.insert(articolo)
}
}
class ArticoliViewModelFactory(private val repository: ArticoliRepository): ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(ArticoliViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return ArticoliViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}

多个片段是否应该共享ViewModel取决于它们是否显示相同的数据。如果它们显示相同的数据,我认为共享ViewModel通常是有意义的,这样当您在它们之间切换时,数据不必从存储库中提取,因此转换更快。如果它们中的任何一个也有大量的唯一数据,您可能会考虑将其拆分为一个单独的ViewModel,这样它就不会在不需要的时候占用内存。

假设你正在使用一个共享的ViewModel,你可以用至少两种不同的方式来实现它,这取决于你喜欢的代码风格。在封装和代码复制之间有一种小小的权衡,尽管它并不是真正的封装,因为它们查看的是同一个实例。因此,我个人更喜欢第二种方法。

  1. 每个ViewModel直接创建ViewModel。如果您使用by activityViewModels(),那么ViewModel将被限定在Activity的范围内,因此它们都将接收到相同的实例。但是由于你的ViewModel需要一个自定义工厂,你必须在两个片段中指定它,所以有一点代码重复:
// In each Fragment:
private val articoliViewModel: ArticoliViewModel by activityViewModels {
ArticoliViewModelFactory((application as ArticoliApplication).repository)
}
  1. 在MainActivity中指定一次ViewModel,并通过cast活动在Fragments中访问它。
// In Activity: The same view model code you already showed in your Activity, but not private
// In Fragments:
private val articoliViewModel: ArticoliViewModel
get() = (activity as MainActivity).articoliViewModel
或者为了避免代码重复,你可以为你的片段创建一个扩展属性,这样他们就不必有这样的代码重复:
val Fragment.articoliViewModel: ArticoliViewModel
get() = (activity as MainActivity).articoliViewModel

最新更新