使用Flow从Room数据库中进行动态组合时未更新。

huangapple go评论69阅读模式
英文:

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 = {&quot;participantId&quot;, &quot;studyId&quot;})
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(&quot;SELECT * FROM Participant ORDER BY participantId ASC&quot;)
     fun getAllParticipants(): List&lt;Participant&gt;
}

The Db helper

interface DatabaseHelper {
    fun getAllSensors(): Flow&lt;List&lt;Sensor&gt;&gt;
    fun getAllParticipants(): Flow&lt;List&lt;Participant&gt;&gt;
}

class AppDatabaseHelper(private val appDatabase: AppDatabase) : DatabaseHelper{
    override fun getAllSensors(): Flow&lt;List&lt;Sensor&gt;&gt; = flow {
        emit(appDatabase.sensorDao().getAllSensors())
    }

    override fun getAllParticipants(): Flow&lt;List&lt;Participant&gt;&gt; = 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&lt;UsersUiState&gt; = _uiState.asStateFlow()
    var participants: List&lt;Participant&gt; = listOf()
    private var appDBHelper: AppDatabaseHelper = AppDatabaseHelper(appDB)

    init {
        viewModelScope.launch {
            appDBHelper.getAllParticipants()
                .flowOn(Dispatchers.IO)
                .catch { e -&gt;
                    Timber.e(&quot;fillUsersList getAllParticipants ex: ${e.message}&quot;)
                }.collect {
                    participants = it
                    _uiState.value = UsersUiState(participants)
                }
        }
    }
}

data class UsersUiState(val participants: List&lt;Participant&gt; = mutableListOf(), val sensors: List&lt;Sensor&gt; = 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> = appDatabase.participantDao().getAllParticipants()
}

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(&quot;SELECT * FROM Participant ORDER BY participantId ASC&quot;)
     fun getAllParticipants(): Flow&lt;List&lt;Participant&gt;&gt;
}

class AppDatabaseHelper(private val appDatabase: AppDatabase) : DatabaseHelper{
    override fun getAllParticipants(): Flow&lt;List&lt;Participant&gt;&gt; = appDatabase.participantDao().getAllParticipants()
}

Reference
https://developer.android.com/training/data-storage/room/async-queries#observable

huangapple
  • 本文由 发表于 2023年6月29日 04:53:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76576637.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定