为什么为我的 viewModel class 实现 ViewModelProvider.Factory 很重要?
Why it is important to implement a ViewModelProvider.Factory for my viewModel class?
我使用数据绑定和 LiveData(这是我经常实现的一段代码)构建了一个基本上包含 Recyclerviewer 和自定义 ViewModel 的片段,但此时发生了运行时异常错误!
/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.tdm_project, PID: 9460
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.tdm_project/com.example.tdm_project.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.example.tdm_project.viewmodel.ArticleViewModel
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2734)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2799)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1537)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6269)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.example.tdm_project.viewmodel.ArticleViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:154)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:211)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:135)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:103)
at com.example.tdm_project.HomeFragment.onCreateView(HomeFragment.kt:75)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2439)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:802)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3273)
at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3229)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:201)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:620)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1248)
at android.app.Activity.performStart(Activity.java:6683)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2697)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2799)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1537)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6269)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
Caused by: java.lang.InstantiationException: java.lang.Class<com.example.tdm_project.viewmodel.ArticleViewModel> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
在谷歌搜索我的问题后,我发现的唯一建议是实现 ViewModelFactory,即使我使用的是 ViewModel class 而不是 AndroidViewModel。
见
ArticleViewModel class
class ArticleViewModel : ViewModel {
//lists
private var articleMList = MutableLiveData<ArrayList<ArticleViewModel>>()
private var articleInnerList = ArrayList<ArticleViewModel>()
constructor(
article: Article
) : super() {
//const with parameters
}
//to observe my list
fun getArticles() : MutableLiveData<ArrayList<ArticleViewModel>>{
articleMList.value = articleInnerList
return articleMList
}
//retrieve data from backend
fun getData() {
//some code
}
}
片段class
class HomeFragment : Fragment() {
//viewmodel
private lateinit var vmodel : ArticleViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
//set the view
rootView = inflater.inflate(R.layout.home_fragment, container, false)
//a function to initialize my recyclerview
intialiserHorizontally()
//creating the instance of viewmodel
vmodel = ViewModelProviders.of(activity!!).get(ArticleViewModel::class.java)
vmodel.getArticles().observe(this, Observer {
customHAdapter.swapData(it)
})
//getting the data from my db
vmodel.getData()
return rootView
}
我的问题是为什么在这种情况下有必要实施ViewModelProvider.Factory?
ViewModel
系统本身只知道如何在 ViewModel
子类上使用零参数构造函数(或 AndroidViewModel
子类使用单参数构造函数)。所以,要么:
根本没有构造函数,或者
有一个明确的零参数构造函数(但考虑摆脱你的另一个,因为没有人应该使用它),或者
实现一个工厂,这样你就可以调用你想要的自定义构造函数
通常,如果您想通过 ViewModelProviders.of(activity).get(ArticleViewModel::class.java)
创建 ViewModel
的实例,那么它需要 ViewModel
的零参数构造函数。如果你想将任何依赖项传递给 ViewModel
构造函数,那么你必须使用工厂,然后你可以通过 ViewModelProviders.of(activity, factory).get(ArticleViewModel::class.java)
.
实例化
建议:
- 使用 dagger 进行依赖注入(它会让你的生活变得轻松 :))
- 在您的 ViewModel 中使用数据列表 class
private var articlesLiveData = MutableLiveData<List<Article>>()
而不是 ViewModel 列表。
我使用数据绑定和 LiveData(这是我经常实现的一段代码)构建了一个基本上包含 Recyclerviewer 和自定义 ViewModel 的片段,但此时发生了运行时异常错误!
/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.tdm_project, PID: 9460
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.tdm_project/com.example.tdm_project.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.example.tdm_project.viewmodel.ArticleViewModel
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2734)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2799)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1537)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6269)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.example.tdm_project.viewmodel.ArticleViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:154)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:211)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:135)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:103)
at com.example.tdm_project.HomeFragment.onCreateView(HomeFragment.kt:75)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2439)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:802)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3273)
at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3229)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:201)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:620)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1248)
at android.app.Activity.performStart(Activity.java:6683)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2697)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2799)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1537)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6269)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
Caused by: java.lang.InstantiationException: java.lang.Class<com.example.tdm_project.viewmodel.ArticleViewModel> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
在谷歌搜索我的问题后,我发现的唯一建议是实现 ViewModelFactory,即使我使用的是 ViewModel class 而不是 AndroidViewModel。
见
ArticleViewModel class
class ArticleViewModel : ViewModel {
//lists
private var articleMList = MutableLiveData<ArrayList<ArticleViewModel>>()
private var articleInnerList = ArrayList<ArticleViewModel>()
constructor(
article: Article
) : super() {
//const with parameters
}
//to observe my list
fun getArticles() : MutableLiveData<ArrayList<ArticleViewModel>>{
articleMList.value = articleInnerList
return articleMList
}
//retrieve data from backend
fun getData() {
//some code
}
}
片段class
class HomeFragment : Fragment() {
//viewmodel
private lateinit var vmodel : ArticleViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
//set the view
rootView = inflater.inflate(R.layout.home_fragment, container, false)
//a function to initialize my recyclerview
intialiserHorizontally()
//creating the instance of viewmodel
vmodel = ViewModelProviders.of(activity!!).get(ArticleViewModel::class.java)
vmodel.getArticles().observe(this, Observer {
customHAdapter.swapData(it)
})
//getting the data from my db
vmodel.getData()
return rootView
}
我的问题是为什么在这种情况下有必要实施ViewModelProvider.Factory?
ViewModel
系统本身只知道如何在 ViewModel
子类上使用零参数构造函数(或 AndroidViewModel
子类使用单参数构造函数)。所以,要么:
根本没有构造函数,或者
有一个明确的零参数构造函数(但考虑摆脱你的另一个,因为没有人应该使用它),或者
实现一个工厂,这样你就可以调用你想要的自定义构造函数
通常,如果您想通过 ViewModelProviders.of(activity).get(ArticleViewModel::class.java)
创建 ViewModel
的实例,那么它需要 ViewModel
的零参数构造函数。如果你想将任何依赖项传递给 ViewModel
构造函数,那么你必须使用工厂,然后你可以通过 ViewModelProviders.of(activity, factory).get(ArticleViewModel::class.java)
.
建议:
- 使用 dagger 进行依赖注入(它会让你的生活变得轻松 :))
- 在您的 ViewModel 中使用数据列表 class
private var articlesLiveData = MutableLiveData<List<Article>>()
而不是 ViewModel 列表。