android 每当尝试从SharedFlow收集数据时,都会获得null

f45qwnt8  于 2023-04-04  发布在  Android
关注(0)|答案(1)|浏览(142)

我在ViewModel中有一个SharedFlow,在那里我调用repository,从数据库中通过一些id检索单个记录。每当用户点击RecyclerView中的一些记录时,都会设置这个参数。问题是我经常得到null,但如果我在repository参数中硬编码id,那么一切都很好。
DAO

@Query("SELECT * FROM employees WHERE id = :id")
fun getEmployeeById(id: Int?): Flow<EmployeeModel>

存储库接口

fun getEmployeeById(id: Int?): Flow<EmployeeModel>

存储库实现

override fun getEmployeeById(id: Int?): Flow<EmployeeModel> {
    return employeeDAO.getEmployeeById(id)
}

视图模型

var employeeById: SharedFlow<DatabaseState<EmployeeModel>> = repository.get().getEmployeeById(employeeId.value?.toInt())
    .map {
        println("onCreateView in VM. ID ${employeeId.value}  |  data: $it")
        DatabaseState.Success(it) }
    .catch { DatabaseState.Error(it.message) }
    .shareIn(viewModelScope, SharingStarted.WhileSubscribed(), replay = 0)

碎片

viewLifecycleOwner.lifecycleScope.launch {
        repeatOnLifecycle(Lifecycle.State.STARTED) {
           mViewModel.employeeById.collect{ employee ->
               when (employee){
                   is DatabaseState.Success -> {
                       Log.i(TAG, "onCreateView APDEJCIK: ${mViewModel.employeeId.value} | ${employee.data}")
                   }
                   is DatabaseState.Error -> {
                       Log.i(TAG, "onCreateView: Failed to retrieve data about employee in UpdateFragmentEmployee fragment")}
               }
           }
        }
    }

正如你所看到的,我从ViewModel中记录了几次ID,它每次都有正确的ID到我点击的位置,所以ID应该没问题。
编辑:模型类

@Entity(tableName = "employees")
data class EmployeeModel(
    @PrimaryKey(autoGenerate = true)
    val id: Int,
    @ColumnInfo(name = "name")
    val name: String,
    @ColumnInfo(name = "surname")
    val surname: String,
    @ColumnInfo(name = "age")
    val age: Int,
    @ColumnInfo(name = "workplace")
    val workplace: String,
    @ColumnInfo(name = "salary")
    val salary: Double
)
biswetbf

biswetbf1#

我认为下面这些代码有问题

var employeeById: SharedFlow<DatabaseState<EmployeeModel>> = repository.get().getEmployeeById(employeeId.value?.toInt())
.map {
    println("onCreateView in VM. ID ${employeeId.value}  |  data: $it")
    DatabaseState.Success(it) }
.catch { DatabaseState.Error(it.message) }
.shareIn(viewModelScope, SharingStarted.WhileSubscribed(), replay = 0)

因为这个声明,你的employeeById将在你的视图模型创建时被创建,所以employeeId.value仍然是null。然后,因为SharingStarted.WhileSubscribed()。map函数只会在你的流在你的repeatOnLifecycle(Lifecycle.State.STARTED)上有一个订阅者时被调用。此时,你的employeeId.value被设置为正确的值。这就是为什么你会得到一个非常奇怪的日志。
为了解决你的问题,我认为有些事情需要改变。
您的DAO

@Query("SELECT * FROM employees WHERE id = :id")
fun getEmployeeById(id: Int): Flow<EmployeeModel?>

你的viewModel。我假设你有一个员工的状态流。你应该使用flatMap来更新你的employeeById值,每当你的员工发生变化时。

val employeeById: SharedFlow<DatabaseState<EmployeeModel>> = employeeId.filterNotNull().flatMapLatest {
   repository.get().getEmployeeById(it.toInt())
}.map {
    if (it!= null) DatabaseState.Success(it) else DatabaseState.Error("NOT FOUND")
}.catch { DatabaseState.Error(it.message) }
.shareIn(viewModelScope, SharingStarted.WhileSubscribed(), replay = 0)

最后,如果使用employeeById显示数据,请考虑使用StateFlow而不是SharedFlow

相关问题