Estou fazendo um curso do JetPack Compose e estou tentando executar um projeto de exemplo mostrando o uso do ViewModel junto com o Hilt.
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
Surface(color = MaterialTheme.colorScheme.background) {
val noteViewModel: NoteViewModel = hiltViewModel<NoteViewModel>()
// NoteApp(noteViewModel)
}
}
}
}
Para inicializar o ViewModel eu também tentei
noteViewModel by viewModels()
e
noteViewModel = hiltViewModel()
O código do ViewModel é o seguinte:
@HiltViewModel
class NoteViewModel @Inject constructor(private val repository: NoteRepository) : ViewModel() {
//private var noteList = mutableStateListOf<Note>()
private val _noteList = MutableStateFlow<List<Note>>(emptyList())
val noteList = _noteList.asStateFlow()
init {
//noteList.addAll(NotesDataSource.loadDataNotes())
viewModelScope.launch(Dispatchers.IO) {
repository.getAllNotes().distinctUntilChanged().collect { listOfNotes ->
if (listOfNotes.isEmpty()) {
Log.d("JetNote", "EmptyList")
} else {
_noteList.value = listOfNotes
}
}
}
}
fun addNote(note: Note) = viewModelScope.launch {
repository.addNote(note)
}
fun updateNote(note: Note) = viewModelScope.launch {
repository.updateNote(note)
}
fun removeNote(note: Note) = viewModelScope.launch {
repository.deleteNote(note)
}
}
A configuração do AppModule para o Hilt é a seguinte:
@InstallIn(SingletonComponent::class)
@Module
object AppModule {
@Singleton
@Provides
fun provideNotesDao(noteDatabase: NoteDatabase) : NoteDatabaseDao = noteDatabase.noteDao()
@Singleton
@Provides
fun provideAppDatabase(@ApplicationContext context: Context) : NoteDatabase =
Room.databaseBuilder(
context,
NoteDatabase::class.java,
"notes_db"
).fallbackToDestructiveMigration().build()
}
Código do NoteRepository:
class NoteRepository @Inject constructor(private val noteDatabaseDao: NoteDatabaseDao) {
suspend fun addNote(note: Note) = noteDatabaseDao.insert(note)
suspend fun updateNote(note: Note) = noteDatabaseDao.update(note)
suspend fun deleteNote(note: Note) = noteDatabaseDao.deleteNote(note)
suspend fun deleteAllNotes() = noteDatabaseDao.deleteAll()
fun getAllNotes(): Flow<List<Note>> = noteDatabaseDao.getNotes().flowOn(Dispatchers.IO).conflate()
}
O erro que recebo ao executar o aplicativo é:
java.lang.RuntimeException: Cannot create an instance of class com.course.jetnote.screens.NoteViewModel
........................
Caused by: java.lang.NoSuchMethodException: com.course.jetnote.screens.NoteViewModel.<init> []
E esta é minha configuração do Gradle:
build.gradle.kts:
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
}
android {
namespace = "com.course.jetnote"
compileSdk = 35
defaultConfig {
applicationId = "com.course.jetnote"
minSdk = 26
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
compose = true
}
packaging {
resources {
excludes += "/META-INF/gradle/incremental.annotation.processors"
excludes += "META-INF/androidx/room/room-compiler-processing/LICENSE.txt"
}
}
}
configurations.implementation {
exclude(group = "org.jetbrains", module = "annotations")
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
implementation(libs.androidx.lifecycle.viewModelCompose)
implementation(libs.hilt.android)
implementation(libs.hilt.compiler)
implementation(libs.androidx.hilt.navigation.compose)
implementation(libs.room.ktx)
implementation(libs.room.runtime)
implementation(libs.room.compiler)
implementation(libs.kotlinx.coroutines.android)
implementation(libs.androidx.room.runtime.android)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
}
lib.versions.toml:
[versions]
agp = "8.8.2"
kotlin = "2.0.0"
coreKtx = "1.15.0"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
lifecycleRuntimeKtx = "2.8.7"
activityCompose = "1.10.1"
composeBom = "2024.04.01"
androidxLifecycle = "2.8.7"
androidxHiltNavigationCompose = "1.0.0"
hilt = "2.56.2"
hiltExt = "1.0.0"
room = "2.6.0"
kotlinxCoroutines = "1.10.0"
kotlinxDatetime = "0.6.0"
kotlinxSerializationJson = "1.8.0"
roomRuntimeAndroid = "2.7.1"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-lifecycle-viewModelCompose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidxLifecycle" }
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
hilt-ext-compiler = { group = "androidx.hilt", name = "hilt-compiler", version.ref = "hiltExt" }
androidx-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "androidxHiltNavigationCompose" }
#Database
room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
#Kotlin Coroutines, serialization, datetime...
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" }
kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinxDatetime" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
androidx-room-runtime-android = { group = "androidx.room", name = "room-runtime-android", version.ref = "roomRuntimeAndroid" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }