如何解决 Android Studio 上的 "Cannot create an instance of class CoursesViewModel" 错误

How to solve "Cannot create an instance of class CoursesViewModel" error on Android Studio

我是 Kotlin 的新手,我正在尝试使用依赖注入 (dagger.hilt) 创建一个 ViewModel 实例。我收到“无法创建 class CoursesViewModel 的实例”错误,我不知道为什么。你能帮我解决这个问题吗?

CoursesViewModel.kt

class CoursesViewModel @ViewModelInject constructor(
        private val courseDao: CourseDao
) : ViewModel() {
}

AppModule.kt

@Module
@InstallIn(ApplicationComponent::class)
object AppModule {

    @Provides
    @Singleton
    fun provideCourseDatabase(
            app: Application,
            callback: CourseDatabase.Callback
    ) = Room.databaseBuilder(app, CourseDatabase::class.java, "course_database")
            .fallbackToDestructiveMigration()
            .addCallback(callback)
            .build()

    @Provides
    fun provideCourseDao(db: CourseDatabase) = db.courseDao()

    @Provides
    @Singleton
    fun provideApplicationScope() = CoroutineScope(SupervisorJob())
}

CourseDatabase.kt

@Database(entities = [Course::class], version = 1)
abstract class CourseDatabase : RoomDatabase() {

    // DbSet equivalent
    abstract fun courseDao(): CourseDao

    // Inner callback class
    class Callback @Inject constructor(
            private val dbProvider: Provider<CourseDatabase>,
            @ApplicationScope
            private val applicationScope: CoroutineScope
    ) : RoomDatabase.Callback(){
        override fun onCreate(database: SupportSQLiteDatabase){
            super.onCreate(database)

            val courseDao = dbProvider.get().courseDao()

            applicationScope.launch {
                courseDao.insert(Course("my course")
            }
        }
    }
}

CoursesAllFragment.kt

class CoursesAllFragment : Fragment() {

    private val viewModel : CoursesViewModel by viewModels()

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment
        val view: View = inflater.inflate(R.layout.fragment_courses_all, container, false)

        // Set the recycler view
        val recyclerView: RecyclerView = view.findViewById(R.id.lectures_classes_recycler_view)
        recyclerView.setHasFixedSize(true)
        recyclerView.setLayoutManager(LinearLayoutManager(context))
        recyclerView.setAdapter(CoursesAllAdapter(viewModel)) // Line 26. see: logcat
        return view
    }
}

logcat 输出:

2021-04-05 23:52:33.202 17137-17137/com.something.something E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.something.something, PID: 17137
    java.lang.RuntimeException: Cannot create an instance of class com.something.something.Courses.CoursesViewModel
        at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221)
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:278)
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:54)
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:41)
        at com.something.something.Courses.Fragments.CoursesAllFragment.getViewModel(Unknown Source:2)
        //In the following line, "CoursesAllFragment.kt:26" is blue, which is where I pass the view model to an RecyclerViewAdapter.
        at com.something.something.Courses.Fragments.CoursesAllFragment.onCreateView(CoursesAllFragment.kt:26)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2950)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:518)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:277)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2177)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2088)
        at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1959)
        at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:306)
        at androidx.fragment.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:249)
        at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1244)
        at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1092)
        at androidx.viewpager.widget.ViewPager.onMeasure(ViewPager.java:1622)
        at android.view.View.measure(View.java:25466)
        at androidx.constraintlayout.widget.ConstraintLayout$Measurer.measure(ConstraintLayout.java:792)
        at androidx.constraintlayout.solver.widgets.ConstraintWidgetContainer.measure(ConstraintWidgetContainer.java:583)
        at androidx.constraintlayout.solver.widgets.ConstraintWidgetContainer.layout(ConstraintWidgetContainer.java:682)
        at androidx.constraintlayout.solver.widgets.analyzer.BasicMeasure.solveLinearSystem(BasicMeasure.java:159)
        at androidx.constraintlayout.solver.widgets.analyzer.BasicMeasure.solverMeasure(BasicMeasure.java:290)
        at androidx.constraintlayout.solver.widgets.ConstraintWidgetContainer.measure(ConstraintWidgetContainer.java:119)
        at androidx.constraintlayout.widget.ConstraintLayout.resolveSystem(ConstraintLayout.java:1578)
        at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java:1690)
        at android.view.View.measure(View.java:25466)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6957)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at android.view.View.measure(View.java:25466)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6957)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at android.view.View.measure(View.java:25466)
        at androidx.constraintlayout.widget.ConstraintLayout$Measurer.measure(ConstraintLayout.java:792)
        at androidx.constraintlayout.solver.widgets.ConstraintWidgetContainer.measure(ConstraintWidgetContainer.java:583)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.verticalSolvingPass(Direct.java:355)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.solveVerticalMatchConstraint(Direct.java:636)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.verticalSolvingPass(Direct.java:407)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.solvingPass(Direct.java:178)
        at androidx.constraintlayout.solver.widgets.ConstraintWidgetContainer.layout(ConstraintWidgetContainer.java:642)
        at androidx.constraintlayout.solver.widgets.analyzer.BasicMeasure.solveLinearSystem(BasicMeasure.java:159)
2021-04-05 23:52:33.202 17137-17137/com.something.something E/AndroidRuntime:     at androidx.constraintlayout.solver.widgets.analyzer.BasicMeasure.solverMeasure(BasicMeasure.java:290)
        at androidx.constraintlayout.solver.widgets.ConstraintWidgetContainer.measure(ConstraintWidgetContainer.java:119)
        at androidx.constraintlayout.widget.ConstraintLayout.resolveSystem(ConstraintLayout.java:1578)
        at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java:1690)
        at android.view.View.measure(View.java:25466)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6957)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at android.view.View.measure(View.java:25466)
        at androidx.constraintlayout.widget.ConstraintLayout$Measurer.measure(ConstraintLayout.java:792)
        at androidx.constraintlayout.solver.widgets.ConstraintWidgetContainer.measure(ConstraintWidgetContainer.java:583)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.verticalSolvingPass(Direct.java:355)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.solveVerticalMatchConstraint(Direct.java:636)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.verticalSolvingPass(Direct.java:455)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.verticalSolvingPass(Direct.java:387)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.solvingPass(Direct.java:178)
        at androidx.constraintlayout.solver.widgets.ConstraintWidgetContainer.layout(ConstraintWidgetContainer.java:642)
        at androidx.constraintlayout.solver.widgets.analyzer.BasicMeasure.solveLinearSystem(BasicMeasure.java:159)
        at androidx.constraintlayout.solver.widgets.analyzer.BasicMeasure.solverMeasure(BasicMeasure.java:290)
        at androidx.constraintlayout.solver.widgets.ConstraintWidgetContainer.measure(ConstraintWidgetContainer.java:119)
        at androidx.constraintlayout.widget.ConstraintLayout.resolveSystem(ConstraintLayout.java:1578)
        at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java:1690)
        at android.view.View.measure(View.java:25466)
        at androidx.drawerlayout.widget.DrawerLayout.onMeasure(DrawerLayout.java:1156)
        at android.view.View.measure(View.java:25466)
        at androidx.constraintlayout.widget.ConstraintLayout$Measurer.measure(ConstraintLayout.java:792)
        at androidx.constraintlayout.solver.widgets.ConstraintWidgetContainer.measure(ConstraintWidgetContainer.java:583)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.verticalSolvingPass(Direct.java:355)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.solveVerticalMatchConstraint(Direct.java:636)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.verticalSolvingPass(Direct.java:407)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.verticalSolvingPass(Direct.java:446)
        at androidx.constraintlayout.solver.widgets.analyzer.Direct.solvingPass(Direct.java:178)
        at androidx.constraintlayout.solver.widgets.ConstraintWidgetContainer.layout(ConstraintWidgetContainer.java:642)
        at androidx.constraintlayout.solver.widgets.analyzer.BasicMeasure.solveLinearSystem(BasicMeasure.java:159)

由于问题正文中的代码过多,Whosebug 不允许我粘贴 logcat 输出的其余部分。

您需要用 @AndroidEntryPoint 标记您的片段和包含它们的活动,让 Hilt 知道要在那里注入。

此外,最新版本的 Hilt 已弃用 @ViewModelInject 注释,转而使用 @HiltViewModel 注释实际视图模型 class 并使用标准 Dagger @Inject 注释在构造函数上。