Я новичок в программировании на Kotlin в студии Android и в настоящее время пытаюсь настроить базу данных комнат для своего проекта, но во время выполнения получаю кучу ошибок, которые не знаю, как исправить. Приложение предназначено для отображения списка имен в формате пейджера с возможностью перелистывания с использованием Jetpack Compose для пользовательского интерфейса, Room для хранения локальной базы данных, ViewModel для управления данными приложения, репозитория, ViewModelFactory для внедрения репозитория в модель представления и класса базы данных. для доступа к DAO. Подскажите, пожалуйста, что я упускаю или делаю неправильно?
Вот список ошибок, которые я получаю:
2024-06-23 10:13:58.120 26589-26589 System com.example.tutorialfollowing
W ClassLoader referenced unknown path: /data/app/com.example.tutorialfollowing-2/lib/x86
2024-06-23 10:13:58.145 26589-26589 AndroidRuntime com.example.tutorialfollowing
D Shutting down VM
2024-06-23 10:13:58.145 26589-26589 AndroidRuntime com.example.tutorialfollowing
E FATAL EXCEPTION: main (Ask Gemini)
Process: com.example.tutorialfollowing, PID: 26589
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.tutorialfollowing/com.example.tutorialfollowing.MainActivity}: java.lang.RuntimeException: Cannot find implementation for com.example.tutorialfollowing.AppDatabase. AppDatabase_Impl does not exist
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
Caused by: java.lang.RuntimeException: Cannot find implementation for com.example.tutorialfollowing.AppDatabase. AppDatabase_Impl does not exist
at androidx.room.Room.getGeneratedImplementation(Room.kt:58)
at androidx.room.RoomDatabase$Builder.build(RoomDatabase.kt:1351)
at com.example.tutorialfollowing.MainActivity.onCreate(MainActivity.kt:54)
at android.app.Activity.performCreate(Activity.java:6662)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
Для контекста вот код моего MainActivity.kt:
import android.os.Bundle
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.ui.graphics.Color
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.pager.PageSize
import androidx.compose.foundation.pager.PagerDefaults
import androidx.compose.foundation.pager.PagerScope
import androidx.compose.material3.Scaffold
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.ui.Alignment
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.room.Room
import androidx.compose.ui.unit.dp
import com.example.tutorialfollowing.ui.theme.TutorialFollowingTheme
class MainActivity : ComponentActivity() {
private lateinit var database: AppDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
database = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java, "names-database"
).build()
val nameDao = database.nameDao()
val repository = NameRepository(nameDao)
val viewModel: NameViewModel by viewModels { NameViewModelFactory(repository) }
setContent {
TutorialFollowingTheme {
val names by viewModel.allNames.observeAsState(emptyList())
NamePagerScreen(names)
}
}
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun NamePagerScreen(names: List<Name>) {
val pagerState = rememberPagerState(
initialPage = 0,
initialPageOffsetFraction = 0f
) {
names.size
}
Box(modifier = Modifier.fillMaxSize()) {
HorizontalPager(
state = pagerState
) { page ->
val name = names[page]
val background = when (name.gender) {
"Girl" -> R.drawable.pink
"Boy" -> R.drawable.blue
else -> R.drawable.default_background
}
Box(modifier = Modifier.fillMaxSize()) {
Image(
painter = painterResource(id = background),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
Box(
modifier = Modifier
.align(Alignment.Center)
.background(Color(0x80000000))
.fillMaxWidth()
.padding(16.dp)
) {
Text(
text = "${name.childFirstName} - ${name.gender}",
style = MaterialTheme.typography.headlineMedium,
color = Color.White,
modifier = Modifier.align(Alignment.Center)
)
}
}
}
}
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
TutorialFollowingTheme {
NamePagerScreen(
listOf(
Name(1, 2020, "Girl", "Asian", "Lily", 10, 1),
Name(2, 2020, "Boy", "Hispanic", "Joel", 8, 2)
)
)
}
}
вот мой класс данных «Name.kt»:
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "names")
data class Name(
@PrimaryKey(autoGenerate = true) val nameId: Int,
@ColumnInfo(name = "year_of_birth") val yearOfBirth: Int,
@ColumnInfo(name = "gender") val gender: String,
@ColumnInfo(name = "ethnicity") val ethnicity: String,
@ColumnInfo(name = "child_first_name") val childFirstName: String,
@ColumnInfo(name = "count") val count: Int,
@ColumnInfo(name = "rank") val rank: Int
)
Класс базы данных «appDatabase»
import androidx.room.Database
import androidx.room.RoomDatabase
@Database(entities = [Name::class], version = 1)
abstract class AppDatabase: RoomDatabase(){
abstract fun nameDao(): NameDao
}
Файл интерфейса DAO «NameDao»:
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import kotlinx.coroutines.flow.Flow
@Dao
interface NameDao {
@Query("SELECT * FROM names")
fun getAll(): Flow<List<Name>>
@Insert
fun insertAll(vararg names: Name)
}
класс 'NameRepository':
импортировать androidx.annotation.WorkerThread импортировать kotlinx.coroutines.flow.Flow
класс NameRepository (частное значение nameDao: NameDao) {
val allNames: Flow<List<Name>> = nameDao.getAll()
@WorkerThread
suspend fun insert(name: Name) {
nameDao.insertAll(name)
}
} Класс «NameViewModel»:
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
class NameViewModel (private val repository: NameRepository) : ViewModel() {
private val _allNames = MutableLiveData<List<Name>>()
val allNames: LiveData<List<Name>> = _allNames
init {
viewModelScope.launch {
repository.allNames.collect { names ->
_allNames.value = names
}
}
}
fun insert(name: Name) = viewModelScope.launch {
repository.insert(name)
}
}
файл класса «NameViewModelFactory»:
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
class NameViewModelFactory(private val repository: NameRepository) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(NameViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return NameViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
libs.Versions.toml:
[versions]
agp = "8.4.1"
kotlin = "1.9.0"
coreKtx = "1.13.1"
junit = "4.13.2"
junitVersion = "1.1.5"
espressoCore = "3.5.1"
lifecycleRuntimeKtx = "2.8.1"
activityCompose = "1.9.0"
composeBom = "2023.08.00"
room = "2.6.1"
roomCommon = "2.6.1"
runtimeLivedata = "1.6.8"
org-jetbrains-kotlin-android = "1.8.0"
[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" }
room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
androidx-room-common = { group = "androidx.room", name = "room-common", version.ref = "roomCommon" }
androidx-runtime-livedata = { group = "androidx.compose.runtime", name = "runtime-livedata", version.ref = "runtimeLivedata" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
org-jetbrains-kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "org-jetbrains-kotlin-android" }
Build.gradle.kts (приложение):
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.jetbrains.kotlin.android) apply false
alias(libs.plugins.org.jetbrains.kotlin.kapt) apply false
}
Build.gradle.kts(модуль):
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.org.jetbrains.kotlin.kapt)
}
android {
namespace = "com.example.tutorialfollowing"
compileSdk = 34
defaultConfig {
applicationId = "com.example.tutorialfollowing"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}
buildTypes {
release {
isMinifyEnabled = 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"
}
buildFeatures {
compose = true
dataBinding =true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.1"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}
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.room.common)
implementation(libs.room.ktx)
implementation(libs.androidx.runtime.livedata)
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)
}
Из какого-то источника, который я нашел в Интернете от людей, получающих подобные ошибки, можно предположить, что это может быть связано с какой-то неправильной конфигурацией в настройке проекта. Я пытался изменить его, но все равно получал те же ошибки.
Вам необходимо добавить необходимые зависимости room-compiler
и room-runtime
, обновить Kotlin до версии 2.0.0
и добавить плагин KSP.
В build.gradle.kts(:app)
plugins {
//...
alias(libs.plugins.kotlinAndroidKsp)
}
dependecies {
// ...
implementation(libs.androidx.room.ktx)
implementation(libs.androidx.room.runtime)
ksp(libs.androidx.room.compiler)
}
build.gradle.kts(проект)
plugins {
// ...
alias(libs.plugins.kotlinAndroidKsp) apply false
}
libs.versions.toml
[versions]
kotlin = "2.0.0"
room = "2.6.1"
ksp = "2.0.0-1.0.22"
[libraries]
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
[plugins]
kotlinAndroidKsp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
должен ли я просто добавить эти зависимости или мне также нужно удалить что-нибудь, например, зависимости «kapt»?
Да, нужно заменить капт на ксп
Большое вам спасибо, я последовал вашему совету и включил последнюю версию Jetpack Compose, и это решило проблемы с ошибками. однако когда я запускаю приложение, появляется белый пустой экран и ничего не происходит.
Приятного кодирования...!
@ user25678140: Это похоже на еще один вопрос, который вы можете задать. Если ответ Амардурая решил проблему из вашего вопроса, вам следует принять его, нажав галочку слева.
Пожалуйста, уточните вашу конкретную проблему или предоставьте дополнительную информацию, чтобы выделить именно то, что вам нужно. Поскольку сейчас написано, трудно точно сказать, о чем вы спрашиваете.