lacas
lacas

Reputation: 14066

Cannot create an instance of class ViewModel kotlin

Here is my code

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)
    }
}

This is from the google samples.. After I want to:

class BookmarkListFragment : FirstFragment() {

private var viewModel: BookmarkViewModel? = null
..

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        viewModel = ViewModelProviders.of(activity!!).get(BookmarkViewModel::class.java)
...

And here is the problem:

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

Can I use this in a fragment?

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) 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.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) 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)  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 find implementation for com.lacas.asd.db.room.BookmarkDb. BookmarkDb_Impl does not exist at android.arch.persistence.room.Room.getGeneratedImplementation(Room.java:93) at android.arch.persistence.room.RoomDatabase$Builder.build(RoomDatabase.java:630) at com.lacas.asd.db.room.BookmarkDb$Companion.get(BookmarkDb.kt:29) at com.lacas.asd.db.room.BookmarkViewModel.(BookmarkViewModel.kt:14) 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)  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)  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) 

Upvotes: 17

Views: 24728

Answers (11)

Lucas
Lucas

Reputation: 753

What was needed in my case. In build.gradle(:app), in the plugins block:

    id 'kotlin-kapt'

In the dependencies block:

implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'

In the class Fragment, where Fragment is your Fragment name:

    private lateinit var  viewModel : ViewModel

In OnViewCreated of your Fragment:

        viewModel = ViewModelProvider(this, ViewModelFactory()).get(ViewModel::class.java)

where ViewModel and ViewModelFactory are your ViewModel and ViewModelFactory names respectively.

Also, if you passed some variable in your ViewModel and ViewModelFactory, like private val repository: Repository or private val mydao:MyDao, make sure to add them to viewModel declaration this way:

next to lateinit viewModel at the beginning of the Fragment class:

    private val myRoomDatabase : MyRoomDatabase by lazy { MyRoomDatabase.getDatabase(requireContext()) }

then, still in OnViewCreated:

        viewModel = ViewModelProvider(this, ViewModelFactory(myRoomDatabase.myDao())).get(ViewModel::class.java)

or, even better, use indexing instead of

.get

    viewModel = ViewModelProvider(this, ItemListViewModelFactory(notesRoomDatabase.notesDao()))[ItemListViewModel::class.java]

Upvotes: 0

eggsloveoats
eggsloveoats

Reputation: 573

For anyone who found none of the above solutions worked:

Double-check if you allowed Room to execute in the main thread. In this case, the ViewModel is trying to construct in the main thread, while Room's builder rejects it.

Upvotes: 0

yusufgltc
yusufgltc

Reputation: 61

Fragment or Activity should need @AndroidEntryPoint for instance if you use Dagger/Hil

Upvotes: 1

Quick learner
Quick learner

Reputation: 11457

I fixed the same problem by doing this.

Added the annotation.

class AlertViewModel
@Inject
constructor(private val userRepository: AlertRepository) : ViewModel(){
    val getList:LiveData<List<Alert>> get() =
        userRepository.getList.flowOn(Dispatchers.Main)
            .asLiveData(context = viewModelScope.coroutineContext)

    fun insert(user:Alert){
        viewModelScope.launch {
            userRepository.insert(user)
        }
    }
}

To

@HiltViewModel // Added this annotation
class AlertViewModel
@Inject
constructor(private val userRepository: AlertRepository) : ViewModel(){
    val getList:LiveData<List<Alert>> get() =
        userRepository.getList.flowOn(Dispatchers.Main)
            .asLiveData(context = viewModelScope.coroutineContext)

    fun insert(user:Alert){
        viewModelScope.launch {
            userRepository.insert(user)
        }
    }
}

Upvotes: 1

lacas
lacas

Reputation: 14066

As somebody said here:

Android room persistent: AppDatabase_Impl does not exist

the solution was:

implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"

implementation "androidx.room:room-runtime:$roomVersion"
kapt "androidx.room:room-compiler:$roomVersion"


implementation "androidx.paging:paging-runtime:$paging_version"
    

Upvotes: 14

sooraj s
sooraj s

Reputation: 1

In my case this implementation solved my problem

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"

before I implemented this only implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"

Upvotes: 0

Sana Ebadi
Sana Ebadi

Reputation: 7220

in, my case I was added private set in DatabaseClass :| I removed it.

  private var INSTANCE: NoteDatabase? = null
            private set

to :

private var INSTANCE: NoteDatabase? = null

this problem take my 2 hours :|||

Upvotes: 1

Dawit Abraham
Dawit Abraham

Reputation: 1752

In my case, I had forgotten to annotate my DatabaseClass class with

@Database(entities = [Book::class], version = 1)
abstract class BookRoomDatabase: RoomDatabase() 

Upvotes: 0

nb2998
nb2998

Reputation: 469

These 3 things worked for me:

  1. Adding/keeping both annotationProcessor and Kapt in the dependencies

annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" kapt "android.arch.lifecycle:compiler:$lifecycle_version"

annotationProcessor "android.arch.persistence.room:compiler:$room_version" kapt "android.arch.persistence.room:compiler:$room_version"

  1. Addingapply plugin: 'kotlin-kapt' at the top of build.gradle(app) and cleaning the project

  2. Re-installing the application

Upvotes: 1

Jamal S
Jamal S

Reputation: 1835

remove kapt "xxxx.xxx." if you still use that in you gradle.build since it'e been deprecated and add

apply plugin: 'kotlin-kapt'

at the end of your gradle.build for the app module. that fixed my problem in android studio 3.1

Upvotes: 4

Rene Ferrari
Rene Ferrari

Reputation: 4206

Change viewModel = ViewModelProviders.of(activity!!).get(BookmarkViewModel::class.java)

to viewModel = ViewModelProviders.of(this).get(BookmarkViewModel::class.java)

Furthermore don't instantiate the viewModel to null. Change it to a lateinit var this way you don't have to instantiate immediately (but you are telling Kotlin that you will instantiate it before accessing it). You can do this like so: private lateinit var viewModel: BookMarkViewModel

EDIT The root of the problem was that the Room Dependencies where either not on the same version or annotationProcessor was used instead of kapt (kapt is required when using Kotlin)

Upvotes: 8

Related Questions