英文:
Dynamic composable with Flow from Room Db not updating
问题
我有一个应用程序,用户界面由来自数据库的对象列表组成。这些对象在后台业务逻辑代码中进行更新。可组合部分在首次合成时正确填充,但从不更新。在初次合成时,VM 的收集中断点被触发,但与 App Inspection 验证的表更新不一致。
出于简洁起见,我已删除了映射到 UI 的额外字段和代码。
任何帮助都将不胜感激!!!
实体:
@Entity(primaryKeys = {"participantId", "studyId"})
public class Participant {
// ******
// 必需的参数
// ******
@NonNull @ColumnInfo
public String participantId;
@NonNull @ColumnInfo
public String studyId;
// 其他字段在此处添加
public Participant(@NonNull String participantId, @NonNull String studyId) {
this.participantId = participantId;
this.studyId = studyId;
}
}
Dao:
@Dao
interface ParticipantDao {
@Insert
fun insertParticipant(participant: Participant): Long
@Delete
fun deleteParticipant(participant: Participant)
@Query("SELECT * FROM Participant ORDER BY participantId ASC")
fun getAllParticipants(): List<Participant>
}
Db 助手:
interface DatabaseHelper {
fun getAllSensors(): Flow<List<Sensor>>
fun getAllParticipants(): Flow<List<Participant>>
}
class AppDatabaseHelper(private val appDatabase: AppDatabase) : DatabaseHelper{
override fun getAllSensors(): Flow<List<Sensor>> = flow {
emit(appDatabase.sensorDao().getAllSensors())
}
override fun getAllParticipants(): Flow<List<Participant>> = flow {
emit(appDatabase.participantDao().getAllParticipants())
}
}
可组合部分:
@Composable
fun Users(navController: NavHostController, usersVM: UsersVM){
val uiState by usersVM.uiState.collectAsState()
usersVM.navController = navController
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth()
) {
if(uiState.participants.isNotEmpty()) {
for(participant in uiState.participants) {
// 显示用户
}
}
}
}
VM:
class UsersVM(private val appDB: AppDatabase): ViewModel() {
private val _uiState = MutableStateFlow(UsersUiState())
val uiState: StateFlow<UsersUiState> = _uiState.asStateFlow()
var participants: List<Participant> = listOf()
private var appDBHelper: AppDatabaseHelper = AppDatabaseHelper(appDB)
init {
viewModelScope.launch {
appDBHelper.getAllParticipants()
.flowOn(Dispatchers.IO)
.catch { e ->
Timber.e("fillUsersList getAllParticipants ex: ${e.message}")
}.collect {
participants = it
_uiState.value = UsersUiState(participants)
}
}
}
}
data class UsersUiState(val participants: List<Participant> = mutableListOf(), val sensors: List<Sensor> = mutableListOf())
英文:
I have an app where the users screen is made up of a list of objects from the DB. Those objects are updated in the background business logic code. The composable is filled correctly on first compose but is never updated. Breakpoints in the VMs collect are fired when upon initial composition, but not when the tables are updated as verified with App Inspection.
I've removed the extra fields and code that maps everything to the UI for brevity.
Any help would be appreciated!!!
The Entity
@Entity(primaryKeys = {"participantId", "studyId"})
public class Participant {
//******
//Required parameters
//******
@NonNull @ColumnInfo
public String participantId;
@NonNull @ColumnInfo
public String studyId;
//Other fields go here
public Participant(@NonNull String participantId, @NonNull String studyId) {
this.participantId = participantId;
this.studyId = studyId;
}
}
The Dao
@Dao
interface ParticipantDao {
@Insert
fun insertParticipant(participant: Participant): Long
@Delete
fun deleteParticipant(participant: Participant)
@Query("SELECT * FROM Participant ORDER BY participantId ASC")
fun getAllParticipants(): List<Participant>
}
The Db helper
interface DatabaseHelper {
fun getAllSensors(): Flow<List<Sensor>>
fun getAllParticipants(): Flow<List<Participant>>
}
class AppDatabaseHelper(private val appDatabase: AppDatabase) : DatabaseHelper{
override fun getAllSensors(): Flow<List<Sensor>> = flow {
emit(appDatabase.sensorDao().getAllSensors())
}
override fun getAllParticipants(): Flow<List<Participant>> = flow {
emit(appDatabase.participantDao().getAllParticipants())
}
}
The composable
@Composable
fun Users(navController: NavHostController, usersVM: UsersVM){
val uiState by usersVM.uiState.collectAsState()
usersVM.navController = navController
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth()
) {
if(uiState.participants.isNotEmpty()) {
for(participant in uiState.participants) {
//Display the users
}
}
}
}
The VM
class UsersVM(private val appDB: AppDatabase): ViewModel() {
private val _uiState = MutableStateFlow(UsersUiState())
val uiState: StateFlow<UsersUiState> = _uiState.asStateFlow()
var participants: List<Participant> = listOf()
private var appDBHelper: AppDatabaseHelper = AppDatabaseHelper(appDB)
init {
viewModelScope.launch {
appDBHelper.getAllParticipants()
.flowOn(Dispatchers.IO)
.catch { e ->
Timber.e("fillUsersList getAllParticipants ex: ${e.message}")
}.collect {
participants = it
_uiState.value = UsersUiState(participants)
}
}
}
}
data class UsersUiState(val participants: List<Participant> = mutableListOf(), val sensors: List<Sensor> = mutableListOf())
答案1
得分: 1
The Dao is returning a List
and not a Flow
.
For observable data, you have to return Flow
from Dao.
Dao
@Dao
interface ParticipantDao {
@Query("SELECT * FROM Participant ORDER BY participantId ASC")
fun getAllParticipants(): Flow<List<Participant>>
}
class AppDatabaseHelper(private val appDatabase: AppDatabase) : DatabaseHelper{
override fun getAllParticipants(): Flow<List
}
Reference
https://developer.android.com/training/data-storage/room/async-queries#observable
英文:
The Dao is returning a List
and not a Flow
.
For observable data, you have to return Flow
from Dao.
Dao
@Dao
interface ParticipantDao {
@Query("SELECT * FROM Participant ORDER BY participantId ASC")
fun getAllParticipants(): Flow<List<Participant>>
}
class AppDatabaseHelper(private val appDatabase: AppDatabase) : DatabaseHelper{
override fun getAllParticipants(): Flow<List<Participant>> = appDatabase.participantDao().getAllParticipants()
}
Reference
https://developer.android.com/training/data-storage/room/async-queries#observable
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论