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

How should i use ViewModel in two fragments?

我有一个包含一个 activity 和两个片段的应用程序,在第一个片段中,我应该能够将数据插入数据库,在第二个片段中,我应该能够在recyclerView.

所以我制作了数据库、我的 RecyclerView 适配器和 ViewModel,

现在的问题是我应该如何管理所有这些?

我是否应该在 activity 中初始化 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 需要一个自定义工厂,你必须在两个 Fragments 中指定它,所以有一点代码重复:
// In each Fragment:
private val articoliViewModel: ArticoliViewModel by activityViewModels {
    ArticoliViewModelFactory((application as ArticoliApplication).repository)
}
  1. 在 MainActivity 中指定 ViewModel 一次,然后通过转换 activity.
  2. 在 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