为什么为我的viewModel类实现ViewModelProvider.Factory很重要?

4
我已经建立了一个包含自定义ViewModel的Recyclerviewer片段,使用数据绑定和LiveData来处理我的数据类型(这是我经常实现的代码),但这一次发生了运行时异常错误!
/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类而不是AndroidViewModel。

请参见此答案

ArticleViewModel类



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 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?

但是在这个时候发生了运行时异常错误!-- 请编辑您的问题并提供堆栈跟踪。 - CommonsWare
1
你在问题中的ArticleViewModel代码无法编译,所以你项目中的代码与问题中的不同。因此,我们将不得不猜测。我建议删除你的第二个构造函数,因为你没有使用它,也不需要它,至少根据你问题中的代码。如果你想要那个构造函数并打算使用它,就是你需要工厂的原因,因为ViewModel系统不知道那个构造函数或如何调用它。 - CommonsWare
哦,是的,一旦我添加了另一个没有参数的构造函数,它就起作用了。谢谢! - Zahra
2个回答

3

ViewModel系统本身只知道如何在您的ViewModel子类上使用无参数构造函数(或AndroidViewModel子类的单参数构造函数)。 所以,要么:

  • 完全不要有构造函数,或者

  • 有一个明确的无参数构造函数(但考虑删除其他构造函数,因为没有任何东西应该使用它),或者

  • 实现一个工厂,这样您就可以调用所需的自定义构造函数。


0

通常情况下,如果您想通过ViewModelProviders.of(activity).get(ArticleViewModel::class.java)创建ViewModel的实例,则它期望ViewModel的零参数构造函数。如果您想将任何依赖项传递给ViewModel构造函数,则必须使用工厂,然后可以通过ViewModelProviders.of(activity, factory).get(ArticleViewModel::class.java)进行实例化。

建议:

  1. 使用Dagger进行依赖注入(这将使您的生活更轻松:))
  2. 在您的ViewModel中,使用数据类列表private var articlesLiveData = MutableLiveData<List<Article>>()而不是ViewModels列表。

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