StateFlow, который получает данные из базы данных Room Dao, внедренные в модель представления, не обновляется после dao.Android

Форум для тех, кто программирует под Android
Ответить
Anonymous
 StateFlow, который получает данные из базы данных Room Dao, внедренные в модель представления, не обновляется после dao.

Сообщение Anonymous »

В моем проекте Android Jetpack Compose с базой данных Room ViewModel представляет собой Dao с внедрением рукоятки и имеет свойство типа StateFlow, значение которого является результатом вызова dao.getAll(). Я попытался предварительно заполнить объект моей базы данных, используя функцию ViewModel, которая вызывает dao.insertAll() и вызывает эту функцию из макета создания. Функция dao.insertAll() успешно возвращает список идентификаторов объектов, но соответствующее свойство ViewModel типа StateFlow не обновляется.
Моя ViewModel (частично)

Код: Выделить всё

@HiltViewModel
class CalendarViewModel @Inject constructor(private val scheduleDao : ScheduleDao) : ViewModel() {
private val selectedDate = MutableStateFlow
(LocalDate(2026, 1, 1))
val selectedDateUiState = selectedDate.asStateFlow()
val schedule : StateFlow = scheduleDao.getAll().stateIn(
scope = viewModelScope,
started = SharingStarted.Lazily,
initialValue = emptyList()
)
fun onDateChanged(dateMillis : Long?) {
if(dateMillis != null) {
selectedDate.value = Instant.fromEpochMilliseconds(dateMillis)
.toLocalDateTime(TimeZone.currentSystemDefault()).date
}
}
private fun getScheduleEntities() : List {
val scheduleEntities = mutableListOf()
try {
val startDate = LocalDate(2000, 1, 1)
val endDate = java.time.LocalDate.now().toKotlinLocalDate()
val startTime = java.time.LocalTime.of(9, 0, 0)
val endTime = java.time.LocalTime.of(18, 0, 0)
val timeList = generateSequence(startTime) { it.plusMinutes(30) }.takeWhile { it  item.format(timeFormat) }
}
@TypeConverter
fun stringToListLocalTime(value : String?) : List? {
return value?.split(',')?.map { item ->  LocalTime.parse(item.trim(), timeFormat) }
}
}
Дао:

Код: Выделить всё

@Dao
interface ScheduleDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertOne(vararg scheduleEntity : ScheduleEntity)

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(scheduleEntities : List): List

@Delete
suspend fun delete(scheduleEntity : ScheduleEntity)

@Query("SELECT * FROM ScheduleEntity")
fun getAll() : Flow
}
База данных комнат и модуль Hilt

Код: Выделить всё

@Database(entities = [ScheduleEntity::class], version = 1, exportSchema = false)
@TypeConverters(Converters::class)
abstract class CalendarDatabase : RoomDatabase() {
abstract fun scheduleDao() : ScheduleDao
companion object {
var INSTANCE : CalendarDatabase? = null
fun getDatabase(context: Context) : CalendarDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(context.applicationContext, CalendarDatabase::class.java, "tasks")
.enableMultiInstanceInvalidation()
.build()
INSTANCE = instance
return instance
}
}
}
}

@Module
@InstallIn(SingletonComponent::class)
object TasksModule {
@Provides
@Singleton
fun provideApplicationScope(): CoroutineScope {
return CoroutineScope(SupervisorJob() + Dispatchers.IO)
}
@Provides
@Singleton
fun provideDatabase(
@ApplicationContext context: Context) : CalendarDatabase = CalendarDatabase.getDatabase(context)
@Provides
@Singleton
fun provideScheduleDao(calendarDatabase : CalendarDatabase) : ScheduleDao = calendarDatabase.scheduleDao()
}
Мой макет создания:

Код: Выделить всё

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainLayout(modifier: Modifier? = null, viewModel : CalendarViewModel = hiltViewModel()) {
val selectedDate by viewModel.selectedDateUiState.collectAsStateWithLifecycle()
val schedule by viewModel.schedule.collectAsStateWithLifecycle()
val isLoaded by viewModel.isLoadedUiState.collectAsStateWithLifecycle()
val datePickerState = rememberDatePickerState(initialSelectedDate = selectedDate.toJavaLocalDate())
LaunchedEffect(datePickerState.selectedDateMillis) {
viewModel.onDateChanged(datePickerState.selectedDateMillis)
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top,
modifier = (modifier ?: Modifier)
.fillMaxWidth()
.fillMaxHeight()
) {
if(isLoaded) {
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
.wrapContentHeight()
) {
DatePicker(
state = datePickerState,
modifier = Modifier.size(400.dp)
)
}
SelectedDateAvailableTimeList(Modifier.weight(1f), viewModel)
}
else {
CircularProgressIndicator(
modifier = Modifier.size(200.dp),
color = Color.Blue
)
}
}
}
@Composable
fun SelectedDateAvailableTimeList(modifier : Modifier, viewModel :  CalendarViewModel = hiltViewModel()) {
val time by viewModel.selectedDateAvailableTime.collectAsState()
LazyVerticalGrid(
columns = GridCells.Fixed(7),
userScrollEnabled = false,
horizontalArrangement = Arrangement.spacedBy(space = 10.dp),
verticalArrangement = Arrangement.spacedBy(10.dp),
modifier = modifier.fillMaxWidth().wrapContentHeight().padding(0.dp, 10.dp)
) {
items(time) { curTime ->
BasicTextField(
modifier = Modifier
.wrapContentSize(Alignment.Center),
textStyle = TextStyle(
textAlign = TextAlign.Center,
fontSize = 10.sp,
fontWeight = FontWeight.Normal,
color = Black),
readOnly = true,
value = curTime.format(viewModel.timeFormat),
onValueChange = {},
)
}
}
}
Мои библиотеки libs.versions.toml:

Код: Выделить всё

[versions]
agp = "8.13.2"
kotlin = "2.3.0"
coreKtx = "1.17.0"
lifecycleRuntimeKtx = "2.10.0"
activityCompose = "1.12.2"
composeBom = "2025.12.01"
ksp = "2.3.0"
hilt = "2.57.2"
hiltAndroid = "2.57.2"
hiltAndroidCompiler = "2.57.2"
roomRuntime = "2.8.4"
roomCompiler = "2.8.4"
roomKtx = "2.8.4"
kotlinxDatetime = "0.7.1"
lifecycleViewmodelCompose = "2.10.0"
hiltNavigationCompose = "1.3.0"
lifecycleRuntimeCompose = "2.10.0"

[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
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-compose-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hiltAndroid" }
symbol-processing-api = { group = "com.google.devtools.ksp", name = "symbol-processing-api", version.ref = "ksp" }
hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hiltAndroidCompiler" }
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "roomRuntime" }
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "roomCompiler" }
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "roomKtx" }
kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinxDatetime" }
androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycleViewmodelCompose" }
androidx-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hiltNavigationCompose" }
androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycleRuntimeCompose" }

[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" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
Мой build.gradle.kts:

Код: Выделить всё

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.ksp)
alias(libs.plugins.hilt)
}

android {
namespace = "app.calendar"
compileSdk {
version = release(36)
}

defaultConfig {
applicationId = "app.calendar"
minSdk = 33
targetSdk = 36
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
getByName("debug") {
isDebuggable = true
signingConfig = signingConfigs.getByName("debug")
}
}
testBuildType = "debug"
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlin {
jvmToolchain(17)
}
buildFeatures {
compose = true
}
tasks.withType().configureEach {
enabled = false
}
androidComponents {
beforeVariants { variantBuilder ->
(variantBuilder as HasHostTestsBuilder).hostTests.get(HostTestBuilder.UNIT_TEST_TYPE)?.enable = false
variantBuilder.enableAndroidTest = false
}
}
}
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.compose.ui)
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.material3)
implementation(libs.symbol.processing.api)
implementation(libs.hilt.android)
implementation(libs.androidx.lifecycle.runtime.compose)
ksp(libs.hilt.android.compiler)
implementation(libs.androidx.hilt.navigation.compose)
implementation(libs.androidx.room.runtime)
ksp(libs.androidx.room.compiler)
implementation(libs.androidx.room.ktx)
implementation(libs.kotlinx.datetime)
implementation(libs.androidx.lifecycle.viewmodel.compose)
debugImplementation(libs.androidx.compose.ui.tooling)
debugImplementation(libs.androidx.compose.ui.test.manifest)
}
Я также пробовал использовать RefreshTrigger:

Код: Выделить всё

private val refreshTrigger = MutableSharedFlow(replay = 1).apply { tryEmit(Unit) }
val schedule : StateFlow = refreshTrigger.flatMapLatest { scheduleDao.getAll() }.stateIn(
scope = viewModelScope,
started = SharingStarted.Lazily,
initialValue = emptyList()
)
...
scheduleEntities = getScheduleEntities()
val scheduleIds = scheduleDao.insertAll(scheduleEntities)
refreshTrigger.emit(Unit)
Но это не помогло. Как я могу решить эту проблему?
Репозиторий моего проекта

Подробнее здесь: https://stackoverflow.com/questions/798 ... del-is-not
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»