You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中无法创建AndroidViewModel实例,能否在Fragment中使用?

问题:Android ViewModel无法在Fragment中创建实例?

问题背景

我参考Google示例实现了BookmarkViewModel,但在Fragment中尝试获取该ViewModel实例时,出现了无法创建实例的报错。

ViewModel代码

class BookmarkViewModel(app: Application) : AndroidViewModel(app) {
    private val dao = BookmarkDb.get(app).bookmarkDao()

    companion object {
        private const val PAGE_SIZE = PagingConstants.PERPAGE
        /**
         * If placeholders are enabled, PagedList will report the full size but some items might
         * be null in onBind method (PagedListAdapter triggers a rebind when data is loaded).
         * <p>
         * If placeholders are disabled, onBind will never receive null but as more pages are
         * loaded, the scrollbars will jitter as new pages are loaded. You should probably disable
         * scrollbars if you disable placeholders.
         */
        private const val ENABLE_PLACEHOLDERS = true
    }

    val allBookmarks = LivePagedListBuilder(dao.allBookmarkByDatetime(), PagedList.Config.Builder()
        .setPageSize(PAGE_SIZE)
        .setEnablePlaceholders(ENABLE_PLACEHOLDERS)
        .build()).build()

    fun insert(title: String, description: String, datetime: String) = ioThread {
        dao.insert(Bookmark(id = 0, title = title, description = description, datetime = datetime))
    }

    fun remove(bookmark: Bookmark) = ioThread {
        dao.delete(bookmark)
    }
}

Fragment中使用代码

class BookmarkListFragment : FirstFragment() {
    private var viewModel: BookmarkViewModel? = null
    ..
    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProviders.of(activity!!).get(BookmarkViewModel::class.java)
        ...

报错信息

java.lang.RuntimeException: Cannot create an instance of class com.lacas.db.room.BookmarkViewModel

完整堆栈:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.lacas.asd/com.lacas.asd.ui.activities.testtabs.TestTab2Activity}: java.lang.RuntimeException: Cannot create an instance of class com.lacas.asd.db.room.BookmarkViewModel
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2924)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2985)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1635)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.lacas.asd.db.room.BookmarkViewModel
at android.arch.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:207)
at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:134)
at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:102)
at com.lacas.asd.ui.activities.testtabs.TestTab2Activity$viewModel$2.invoke(TestTab2Activity.kt:34)
at com.lacas.asd.ui.activities.testtabs.TestTab2Activity$viewModel$2.invoke(TestTab2Activity.kt:29)
at kotlin.UnsafeLazyImpl.getValue(Lazy.kt:154)
at com.lacas.asd.ui.activities.testtabs.TestTab2Activity.getViewModel(TestTab2Activity.kt)
at com.lacas.asd.ui.activities.testtabs.TestTab2Activity.onCreated(TestTab2Activity.kt:45)
at com.lacas.asd.base.BasePermissionsActivity.onCreate(BasePermissionsActivity.kt:34)
at android.app.Activity.performCreate(Activity.java:6912)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2877)
... 11 more
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
at android.arch.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:199)
... 22 more

请问该ViewModel能否在Fragment中使用?如何解决无法创建实例的问题?


解答

首先明确:这个ViewModel完全可以在Fragment中使用,问题出在ViewModel的实例获取方式或者依赖初始化环节上。我来帮你一步步分析解决:

1. 分析报错根源

从堆栈信息看,核心异常是InvocationTargetException,这说明ViewModel的构造函数在通过反射创建时,内部执行的代码抛出了异常。结合你的ViewModel代码,最可能的问题点是BookmarkDb.get(app).bookmarkDao()这一行——如果数据库初始化失败,就会导致ViewModel创建失败。

另外,你使用的ViewModelProviders.of()是已经被废弃的API,这也可能带来兼容性问题。

2. 具体解决步骤

步骤一:检查数据库初始化是否正常

先单独验证BookmarkDb.get(app)能否成功获取数据库实例:

  • 可以在Application类中提前初始化数据库,或者在ViewModel构造函数中添加日志/调试断点,确认BookmarkDb.get(app)没有抛出异常(比如Room实体类注解错误、数据库版本冲突、缺少Room依赖等)。
  • 如果数据库初始化有问题,先修复数据库相关的错误,比如检查Room的实体类是否正确使用@Entity注解,Dao接口是否正确标注@Dao,数据库类是否继承RoomDatabase并正确配置实体类。

步骤二:替换废弃的ViewModel获取API

旧的ViewModelProviders已经被AndroidX废弃,推荐使用ViewModelProvider的新写法。根据你的需求(和Activity共享ViewModel),修改Fragment中的代码:

// 替换原来的ViewModelProviders.of(activity!!).get(...)
viewModel = ViewModelProvider(requireActivity())[BookmarkViewModel::class.java]

如果你的Fragment需要独立的ViewModel实例(不和Activity共享),则改为:

viewModel = ViewModelProvider(this)[BookmarkViewModel::class.java]

注意:确保你的项目依赖了AndroidX的ViewModel库,比如在build.gradle中包含:

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"

步骤三:确认ViewModel构造函数的正确性

你的ViewModel继承AndroidViewModel是正确的(因为需要Application上下文),Kotlin默认的构造函数是public,所以访问权限没问题。如果之前手动修改过构造函数的访问修饰符,确保它是public的。

3. 验证修复

完成上述步骤后,重新运行项目,ViewModel应该能正常在Fragment中创建实例了。如果还是报错,可以进一步检查:

  • 确认requireActivity()返回的Activity实例是有效的(不要在Fragment未关联Activity时调用)。
  • 检查ioThread函数的实现是否正确,是否会导致线程问题(不过这个是在方法内部调用,不会影响ViewModel创建)。

内容的提问来源于stack exchange,提问作者lacas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:45:26