如何使用带片段的视图模型+房间?
How to use viewmodel + room with fragments?
我正在查看 Android room with a view 的教程,并尝试将他们使用 ViewModels
的模型扩展到多个片段,但不太确定如何。
我的应用程序
class myApplication : Application() {
companion object {
var database: myDatabase? = null
var repository: myRepository? = null
}
override fun onCreate() {
super.onCreate()
database = MyDatabase.getInstance(this)
repository = MyRepository(database!!.myDatabaseDao)
}
}
MyViewModel
class MyViewModel(private val repository: MyRepository) : ViewModel() {
val allWords: LiveData<List<Words>> = repository.allWords.asLiveData()
fun insert(word: Word) = viewModelScope.launch {
repository.insert(word)
}
}
class MyViewModelFactory(private val repository: MyRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MyViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return MyViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
HomeFragment
class HomeFragment : Fragment() {
private val myViewModel: MyViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
var rootView = inflater.inflate(R.layout.fragment_home, container, false)
return rootView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
myViewModel.allWords.observe(viewLifecycleOwner) { words ->
// Update the cached copy of the words in the adapter.
words.let { Log.d("fragment", it.toString()) }
}
}
}
我还有一些其他片段,它们有望与 HomeFragment
共享相同的 ViewModel
。我尝试了很多不同的方法,比如使用
myViewModel = ViewModelProviders.of(activity!!).get(MyViewModel::class.java)
但他们都给我Caused by: java.lang.InstantiationException: java.lang.Class<com.example.tabtester.ViewModels.MyViewModel> has no zero argument constructor
。我找不到任何向我展示如何在 Kotlin 中提供构造函数的 SO 帖子或文档。
此外,从概念上讲,我找不到任何关于到底发生了什么以及视图模型是如何构建的(以及通过什么构建的)的描述。在 Room with a View 教程中,给出的例子在 MainActivity
:
private val wordViewModel: WordViewModel by viewModels {
WordViewModelFactory((application as WordsApplication).repository)
}
对我来说这是有道理的;您正在使用工厂实例化一个 ViewModel 以在 MainActivity 中使用。但是对于如何在片段中使用 ViewModel 的任何描述,我看不到 ViewModel 是在哪里构建的。如果您有多个片段,谁在构建 ViewModel?如果我使用 Fragments 那么这是否意味着我还需要一个 activity 来构造 ViewModel,然后以某种方式在 Fragments 之间共享?
希望得到任何帮助或能更清楚地解释这一点的文档。
by viewModels()
、by activityViewModels()
和 (now deprecated) ViewModelProviders.of()
all feed into one method: the ViewModelProvider constructor:
的底层 API
ViewModelProvider(viewModelStore: ViewModelStore, factory: ViewModelProvider.Factory)
这个构造函数有两个参数:
ViewModelStore
控制您创建的 ViewModel
的存储和范围。例如,当您在 Fragment 中使用 by viewModels()
时,Fragment
用作 ViewModelStore
。同样,by activityViewModels()
使用 Activity
作为 ViewModelStore
。
ViewModelProvider.Factory
控制 ViewModel
的构造,如果尚未为特定 ViewModelStore
创建一个的话。
因此,如果您需要自定义 Factory
,您必须 始终 将该工厂传递到所有可以创建该 ViewModel
的地方(记住,由于处理死亡和重生,不能保证您的 HomeFragment
将是创建您的 ViewModel
) 的第一个片段。
private val myViewModel: MyViewModel by activityViewModels() {
MyViewModelFactory(MyApplication.repository!!)
}
只要您使用 activityViewModels()
,您的 ViewModel
存储将始终处于 activity 级别,无论您使用的是什么工厂。
我正在查看 Android room with a view 的教程,并尝试将他们使用 ViewModels
的模型扩展到多个片段,但不太确定如何。
我的应用程序
class myApplication : Application() {
companion object {
var database: myDatabase? = null
var repository: myRepository? = null
}
override fun onCreate() {
super.onCreate()
database = MyDatabase.getInstance(this)
repository = MyRepository(database!!.myDatabaseDao)
}
}
MyViewModel
class MyViewModel(private val repository: MyRepository) : ViewModel() {
val allWords: LiveData<List<Words>> = repository.allWords.asLiveData()
fun insert(word: Word) = viewModelScope.launch {
repository.insert(word)
}
}
class MyViewModelFactory(private val repository: MyRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MyViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return MyViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
HomeFragment
class HomeFragment : Fragment() {
private val myViewModel: MyViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
var rootView = inflater.inflate(R.layout.fragment_home, container, false)
return rootView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
myViewModel.allWords.observe(viewLifecycleOwner) { words ->
// Update the cached copy of the words in the adapter.
words.let { Log.d("fragment", it.toString()) }
}
}
}
我还有一些其他片段,它们有望与 HomeFragment
共享相同的 ViewModel
。我尝试了很多不同的方法,比如使用
myViewModel = ViewModelProviders.of(activity!!).get(MyViewModel::class.java)
但他们都给我Caused by: java.lang.InstantiationException: java.lang.Class<com.example.tabtester.ViewModels.MyViewModel> has no zero argument constructor
。我找不到任何向我展示如何在 Kotlin 中提供构造函数的 SO 帖子或文档。
此外,从概念上讲,我找不到任何关于到底发生了什么以及视图模型是如何构建的(以及通过什么构建的)的描述。在 Room with a View 教程中,给出的例子在 MainActivity
:
private val wordViewModel: WordViewModel by viewModels {
WordViewModelFactory((application as WordsApplication).repository)
}
对我来说这是有道理的;您正在使用工厂实例化一个 ViewModel 以在 MainActivity 中使用。但是对于如何在片段中使用 ViewModel 的任何描述,我看不到 ViewModel 是在哪里构建的。如果您有多个片段,谁在构建 ViewModel?如果我使用 Fragments 那么这是否意味着我还需要一个 activity 来构造 ViewModel,然后以某种方式在 Fragments 之间共享?
希望得到任何帮助或能更清楚地解释这一点的文档。
by viewModels()
、by activityViewModels()
和 (now deprecated) ViewModelProviders.of()
all feed into one method: the ViewModelProvider constructor:
ViewModelProvider(viewModelStore: ViewModelStore, factory: ViewModelProvider.Factory)
这个构造函数有两个参数:
ViewModelStore
控制您创建的ViewModel
的存储和范围。例如,当您在 Fragment 中使用by viewModels()
时,Fragment
用作ViewModelStore
。同样,by activityViewModels()
使用Activity
作为ViewModelStore
。ViewModelProvider.Factory
控制ViewModel
的构造,如果尚未为特定ViewModelStore
创建一个的话。
因此,如果您需要自定义 Factory
,您必须 始终 将该工厂传递到所有可以创建该 ViewModel
的地方(记住,由于处理死亡和重生,不能保证您的 HomeFragment
将是创建您的 ViewModel
) 的第一个片段。
private val myViewModel: MyViewModel by activityViewModels() {
MyViewModelFactory(MyApplication.repository!!)
}
只要您使用 activityViewModels()
,您的 ViewModel
存储将始终处于 activity 级别,无论您使用的是什么工厂。