Android Kotlin Jetpack Compose - 房间数据库状态问题

问题描述 投票:0回答:1

我实现了一个 Room DB,现在我的状态遇到了这个问题:

我的视图模型

@HiltViewModel
class WorkingDayViewModel @Inject constructor(
    private val repository: WorkingDayRepository
) : ViewModel() {

    companion object{
        private const val MILLS = 5_000L
    }

    val allWorkingDaysState : StateFlow<WorkingDayState> = repository.getAllWorkingDays()
        .map { WorkingDayState(it) }
        .onEach {
            println("All Working Days: $it")
        }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(MILLS),
            initialValue = WorkingDayState()
        )

    fun upsertWorkingDay(workingDay: WorkingDay) {
        viewModelScope.launch {
            repository.upsertWorkingDay(workingDay)
        }
    }
}

我的@Composable

 val workingDays by viewModelWorkingDays.allWorkingDaysState.collectAsState()
        LaunchedEffect(key1 = workingDays) {
            Log.d("workingDays", workingDays.toString())
        }

工作日.kt

@Entity(tableName = "WorkingDays")
data class WorkingDay(

    @PrimaryKey(autoGenerate = false)
    val date: LocalDate,

    val startTime: LocalTime,
    val endTime: LocalTime,
    val pauseTime: Int,
    val fixedHourDayDuration: Int,
    val isFixedHourDay: Boolean,
    var isActive: Boolean,
)

WorkingDayState.kt

data class WorkingDayState(
    val workingDays: List<WorkingDay> = emptyList(),
    val date: LocalDate? = null,
    val startTime: LocalTime? = null,
    val endTime: LocalTime? = null,
    val pauseTime: String = "",
    val fixedHourDayDuration: Int = 0,
    val isFixedHourDay: Boolean = false,
    val isActive: Boolean = true,
)

WorkingDayDao.kt

@Dao
interface WorkingDaysDao {

    @Upsert
    fun upsertWorkingDay(workingDay: WorkingDay)

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun initInsertWorkingDay(workingDay: WorkingDay)

    @Delete
    fun deleteWorkingDay(workingDay: WorkingDay)

    @Query("SELECT * FROM workingdays WHERE date = :date")
    fun getWorkingDayByDate(date: LocalDate): Flow<WorkingDay>

    @Query("SELECT * FROM workingdays")
    fun getAllWorkingDays(): Flow<List<WorkingDay>>

}

WorkingDayRepository.kt

class WorkingDayRepository @Inject constructor(
    private val dao: WorkingDaysDao
) {

    fun upsertWorkingDay(workingDay: WorkingDay) = dao.upsertWorkingDay(workingDay)
    fun initInsertWorkingDay(workingDay: WorkingDay) = dao.initInsertWorkingDay(workingDay)
    fun deleteWorkingDay(workingDay: WorkingDay) = dao.deleteWorkingDay(workingDay)
    fun getWorkingDayByDate(date: LocalDate) = dao.getWorkingDayByDate(date)
    fun getAllWorkingDays() = dao.getAllWorkingDays()

}

类型转换器

class LocalDateConverter {
    @TypeConverter
    fun fromTimestamp(value: Long?): LocalDate? {
        return value?.let {
            ofEpochMilli(it).atZone(ZoneId.systemDefault()).toLocalDate()
        }
    }

    @TypeConverter
    fun dateToTimestamp(date: LocalDate?): Long? {
        return date?.atStartOfDay(ZoneId.systemDefault())?.toInstant()?.toEpochMilli()
    }
}

class LocalTimeConverter {
    @TypeConverter
    fun fromLocalTime(value: LocalTime?): String? {
        return value?.toString()
    }

    @TypeConverter
    fun toLocalTime(value: String?): LocalTime? {
        return value?.let { LocalTime.parse(it) }
    }
}

Git 上的项目: https://github.com/SkAppCoding/DebugTests

现在问题如下:

当我调用 upsertWorkingDay 并更改一些值时。这些值保存在数据库中。 allWorkingDaysState 也会发出一个新状态。打印 Log in .onEach。 但这就是问题开始的地方。我的 LaunchedEffect 未触发。

另一件事是。当我直接使用 Android Studio 中的“App Inspection”更改数据库中的值时,allWorkingDaysState 也会发出一个新值。打印 Log in .onEach。 而且我的 LaunchedEffect 也被触发了。

差别在哪里。我做错了什么?我希望你能帮助我。

我尝试了很多日志消息。但没有任何帮助我找到问题所在。

我希望如果 allWorkingDaysState 在 upsertWorkingDay 之后发出新值,我的 LaunchedEffect 也会被触发。

android kotlin state android-room
1个回答
0
投票

示例代码中缺少最重要的部分,即如何更新数据库。

从您提供的代码来看,只有一件事看起来很明显:您的 Room 实体包含声明为

isActive
的属性
var
。这可能是一个意外,因为所有其他字段都被正确声明为
val
(因为在使用 StateFlows 和 Compose 时这是必要的,对象必须是不可变),但是这个可能会诱使您实际 更改 该值。这是我可以想象您所描述的行为可能发生的唯一情况。

将其更改为

val
,一切都应该没问题。当您想要更改
isActive
时,请按照与所有其他
val
属性相同的方式进行操作:使用
copy
创建一个 new 对象。

val changedWorkingDay = workingDay.copy(isActive = !workingDay.isActive)

如果您要修改旧的

workingDay
对象,Compose 会错误地假设新值与旧值相同,因为它们的所有属性都匹配,并且不会触发重组,也不会更新 UI。

© www.soinside.com 2019 - 2024. All rights reserved.