Can't initialize ViewModelProvider when calling initMainViewModel()

Viewed 15

I got this error when try running this code to show the GitHub API description, name, and avatar image in the android app (still cannot figure it out to fix the error). Any help is welcome :)

This is my app structure:

adapter

|--> RecyclerViewAdapter

database

|--> AppDao

|--> AppDatabase

dependencyinjection

|--> AppModule

model

|--> NewsData

|--> NewsList

|--> Owner

network

|--> RetroRepository

|--> RetroServiceInterface

viewmodel

|--> MainActivityViewModel

MainActivity

MyRoomRetroApplication

================================================================

SOURCE CODE

AppModule

package com.example.newsapplication.dependencyinjection

import android.content.Context
import com.example.newsapplication.database.AppDao
import com.example.newsapplication.database.AppDatabase
import com.example.newsapplication.network.RetroServiceInterface
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
class AppModule {

    @Provides
    @Singleton
    fun getAppDatabase(context: Context): AppDatabase{
        return AppDatabase.getAppDBInstance(context)
    }

    @Provides
    @Singleton
    fun getAppDao(appDatabase: AppDatabase): AppDao{
        return appDatabase.getAppDao()
    }

    val BASE_URL = "https://api.github.com/search/"


    // Function to return instance of RetroServiceInterface + Mark as @Provides and @Singleton
    @Provides
    @Singleton
    fun getRetroServiceInstance(retrofit: Retrofit): RetroServiceInterface{
       return retrofit.create(RetroServiceInterface::class.java)
    }

    // Function to return retrofit instance + Mark as @Provides and @Singleton
    @Provides
    @Singleton
    fun getRetroInstance(): Retrofit{
        return Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
}

NewsData

package com.example.newsapplication.model

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "news") // Table of databases
data class NewsData(
    @PrimaryKey(autoGenerate = true)@ColumnInfo(name = "id")val id: Int = 0,
    @ColumnInfo(name = "name")val name: String?,
    @ColumnInfo(name = "description")val description: String?,
    @ColumnInfo(name = "owner")val owner: Owner)

NewsList

package com.example.newsapplication.model

data class NewsList(val items: List<NewsData>) //Create items list

Owner

package com.example.newsapplication.model

import androidx.room.TypeConverter
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.reflect.TypeToken
import java.lang.reflect.Type

data class Owner(val avatar_url: String?)


class TypeConverterOwner {

    // Type Converter Function
    val gson: Gson = Gson() // Using Gson library to convert Object to String

    @TypeConverter
    fun stringToSomeObjectList(data: String?): Owner? {
        if (data == null) return null
        val listType: Type = object : TypeToken<Owner?>() {}.type
        return gson.fromJson<Owner?>(data, listType)
    }

    @TypeConverter
    fun someObjectListToString(someObject: Owner?): String? {
        return gson.toJson(someObject)
    }
}

RetroRepository

package com.example.newsapplication.network

import androidx.lifecycle.LiveData
import com.example.newsapplication.database.AppDao
import com.example.newsapplication.model.NewsData
import com.example.newsapplication.model.NewsList
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import javax.inject.Inject

// Make the API call in here
// Inject to have the access to RetroServiceInterface and DAO
class RetroRepository @Inject constructor(private val retroServiceInterface: RetroServiceInterface,
                                        private val appDao: AppDao){

    fun getAllRecords(): LiveData<List<NewsData>> {
        return appDao.getAllRecords()
    }

    fun insertRecord(newsData: NewsData){
        appDao.insertRecords(newsData)
    }

    // Get the data from github api ...
    fun makeApiCall(query: String?){
        val call: Call<NewsList> = retroServiceInterface.getDataFromAPI(query!!)
        call?.enqueue(object : Callback<NewsList>{
            override fun onResponse(call: Call<NewsList>, response: Response<NewsList>) {
                if(response.isSuccessful){
                    // Delete all records after getting data, delete data in table and insert with the new fetched data to the table
                    appDao.deleteAllRecords()
                    response.body()?.items?.forEach {
                        insertRecord(it)
                    }
                }
            }

            override fun onFailure(call: Call<NewsList>, t: Throwable) {
                TODO("Not yet implemented")
            }
        })

    }
}

RetroServiceInterface

package com.example.newsapplication.network

import com.example.newsapplication.model.NewsList
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query

interface RetroServiceInterface {

    @GET("repositories")
    fun getDataFromAPI(@Query("q")query: String): Call<NewsList> 

}

MainActivityViewModel

package com.example.newsapplication.viewmodel

import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import com.example.newsapplication.model.NewsData
import com.example.newsapplication.network.RetroRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

// Annotate with HiltViewModel when using Hilt
// Also inject constructor to capture instance of the repositories
@HiltViewModel
class MainActivityViewModel @Inject constructor(private val repository: RetroRepository): ViewModel(){

    fun getAllRepositoryList(): LiveData<List<NewsData>>{
        return repository.getAllRecords()
    }

    fun makeApiCall(){
        repository.makeApiCall("ab")
    }

}

MainActivity

package com.example.newsapplication

import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.newsapplication.adapter.RecyclerViewAdapter
import com.example.newsapplication.model.NewsData
import com.example.newsapplication.viewmodel.MainActivityViewModel
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    private lateinit var recyclerViewAdapter: RecyclerViewAdapter
    private lateinit var context:Context

    // For debug purposes
    //private var TAG:String? = "MyActivity"
    //private var message:String? = ""

    fun setContext(con:Context){
        context = con
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        setContext(this)
        initViewModel()
        initMainViewModel()
    }

    private fun initViewModel(){
        val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
        recyclerView.apply {
            layoutManager = LinearLayoutManager(this@MainActivity)
            val decoration = DividerItemDecoration(applicationContext, DividerItemDecoration.VERTICAL)
            addItemDecoration(decoration)
            recyclerViewAdapter = RecyclerViewAdapter()
            adapter = recyclerViewAdapter
        }
    }

    private fun initMainViewModel(){
        val viewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
        viewModel.getAllRepositoryList().observe(this, Observer<List<NewsData>>{
            recyclerViewAdapter.setListData(it)
            recyclerViewAdapter.notifyDataSetChanged()
        })
        viewModel.makeApiCall()
    }
}

MyRoomRetroApplication

package com.example.newsapplication

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class MyRoomRetroApplication: Application() {

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

news_list_row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView android:id="@+id/image_avatar_url"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_gravity="center"
        android:layout_marginStart="10dp"/>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView android:id="@+id/tvName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:textSize="20sp"
            android:textStyle="bold"
            android:textColor="@color/black"/>

        <TextView android:id="@+id/tvDesc"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:textSize="16sp"
            android:maxLines="3"
            android:textColor="@color/black"/>
    </LinearLayout>

</LinearLayout>

build.gradle (Project)

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    id 'com.android.application' version '7.2.2' apply false
    id 'com.android.library' version '7.2.2' apply false
    id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

build.gradle (App)

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'
}

android {
    compileSdk 32

    defaultConfig {
        applicationId "com.example.newsapplication"
        minSdk 21
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

ext {
    versions = "2.4.3"
}

dependencies {

    implementation 'androidx.core:core-ktx:1.8.0'
    implementation 'androidx.appcompat:appcompat:1.5.0'
    implementation 'com.google.android.material:material:1.6.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

    // Below dependency for using retrofit + gson.
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.google.code.gson:gson:2.8.6'

    // Below dependency for using picasso image loading library
    implementation 'com.squareup.picasso:picasso:2.71828'

    // Kotlin Extensions and Caroutines support for Room
    implementation("androidx.room:room-ktx:$versions")
    // Kotlin Annotation Processing Tool (kapt)
    kapt("androidx.room:room-compiler:$versions")
    implementation("androidx.room:room-runtime:$versions")

    // Test helpers
    testImplementation("androidx.room:room-testing:$versions")

    // Paging 3 Integration
    implementation("androidx.room:room-paging:$versions")

    // Kotlin implementation
    implementation('androidx.navigation:navigation-fragment-ktx:2.5.2')
    implementation('androidx.navigation:navigation-ui-ktx:2.5.2')

    // Recycler view
    implementation('androidx.recyclerview:recyclerview:1.2.1')

    // Feature module support
    implementation('androidx.navigation:navigation-dynamic-features-fragment:2.5.2')

    // Testing navigation
    androidTestImplementation('androidx.navigation:navigation-testing:2.5.2')

    // Jetpack compose integration
    implementation('androidx.navigation:navigation-compose:2.5.2')

    // ViewModel
    implementation('androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1')
    implementation('androidx.lifecycle:lifecycle-extensions:2.2.0')

    // Glide
    implementation('com.github.bumptech.glide:glide:4.12.0')

    // Hilt
    implementation('com.google.dagger:hilt-android:2.33-beta')
    kapt('com.google.dagger:hilt-android:2.33-beta')

    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

Error when try running app:

2022-09-14 22:50:18.249 14537-14537/com.example.newsapplication E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.newsapplication, PID: 14537
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.newsapplication/com.example.newsapplication.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.example.newsapplication.viewmodel.MainActivityViewModel
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3676)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3813)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7898)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
     Caused by: java.lang.RuntimeException: Cannot create an instance of class com.example.newsapplication.viewmodel.MainActivityViewModel
        at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:204)
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:322)
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:304)
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:278)
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.kt:128)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:187)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:153)
        at com.example.newsapplication.MainActivity.initMainViewModel(MainActivity.kt:50)
        at com.example.newsapplication.MainActivity.onCreate(MainActivity.kt:35)
        at android.app.Activity.performCreate(Activity.java:8290)
        at android.app.Activity.performCreate(Activity.java:8269)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1384)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3657)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3813) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loopOnce(Looper.java:201) 
        at android.os.Looper.loop(Looper.java:288) 
        at android.app.ActivityThread.main(ActivityThread.java:7898) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936) 
     Caused by: java.lang.InstantiationException: java.lang.Class<com.example.newsapplication.viewmodel.MainActivityViewModel> has no zero argument constructor
        at java.lang.Class.newInstance(Native Method)
        at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:202)
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:322) 
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:304) 
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:278) 
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.kt:128) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:187) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:153) 
        **at com.example.newsapplication.MainActivity.initMainViewModel(MainActivity.kt:50)** 
        **at com.example.newsapplication.MainActivity.onCreate(MainActivity.kt:35)** 
        at android.app.Activity.performCreate(Activity.java:8290) 
        at android.app.Activity.performCreate(Activity.java:8269) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1384) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3657) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3813) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loopOnce(Looper.java:201) 
        at android.os.Looper.loop(Looper.java:288) 
        at android.app.ActivityThread.main(ActivityThread.java:7898) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936) 
2022-09-14 22:50:18.262 14537-14537/? I/Process: Sending signal. PID: 14537 SIG: 9

 

0 Answers
Related