英文:
Getting null whenever trying to collect data from SharedFlow
问题
以下是您要翻译的代码部分:
DAO
@Query("SELECT * FROM employees WHERE id = :id")
fun getEmployeeById(id: Int?): Flow<EmployeeModel>
RepositoryInterface
fun getEmployeeById(id: Int?): Flow<EmployeeModel>
RepositoryImplementation
override fun getEmployeeById(id: Int?): Flow<EmployeeModel> {
return employeeDAO.getEmployeeById(id)
}
ViewModel
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)
Fragment
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")
}
}
}
}
}
Model class
@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
)
英文:
I have a SharedFlow in ViewModel, where I make a call to repository, to retrieve from the database a single record by some id. This is will be set whenever user will click on some record in RecyclerView. The problem is I constantly getting null, but if I hardcode id in repository parameter, then everything works fine.
DAO
@Query("SELECT * FROM employees WHERE id = :id")
fun getEmployeeById(id: Int?): Flow<EmployeeModel>
RepositoryInterface
fun getEmployeeById(id: Int?): Flow<EmployeeModel>
RepositoryImplementation
override fun getEmployeeById(id: Int?): Flow<EmployeeModel> {
return employeeDAO.getEmployeeById(id)
}
ViewModel
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)
Fragment
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")}
}
}
}
}
As you can see, I'm loging the ID from the ViewModel a couple of times, and it every times has correct id to the position I've clicked, so the ID should be ok.
Edit:
Model class
@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
)
答案1
得分: 0
以下是翻译好的部分:
"I think these code below have a problem"(我认为以下的代码存在问题)
"Because of this declaration, your employeeById will be created when your view model is created, so employeeId.value is still null."(由于这个声明,当您的视图模型创建时,employeeById 将被创建,因此 employeeId.value 仍然为空。)
"Then, because of SharingStarted.WhileSubscribed(), the map function will only get called when your flow has a subscriber on your repeatOnLifecycle(Lifecycle.State.STARTED). At this time, your employeeId.value is set the correct value. This is why you get a very weird log."(然后,由于 SharingStarted.WhileSubscribed(),map 函数只在您的流具有订阅者时才会被调用,例如在 repeatOnLifecycle(Lifecycle.State.STARTED) 上。在这个时候,employeeId.value 将设置为正确的值。这就是为什么您会得到一个非常奇怪的日志。)
"To fix your issue, I think some things need to be changed."(为了解决您的问题,我认为需要做一些更改。)
"Your DAO"(您的数据访问对象)
"Your viewModel. I assume that you have a state flow for your employee. You should use flatMap to update your employeeById value whenever your employee changes."(您的视图模型。我假设您对员工有一个状态流。您应该使用 flatMap 来在员工更改时更新 employeeById 的值。)
"Last thing, if you use employeeById to display data. Consider using StateFlow instead of SharedFlow"(最后一件事,如果您使用 employeeById 来显示数据,请考虑使用 StateFlow 而不是 SharedFlow。)
英文:
I think these code below have a problem
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)
Because of this declaration, your employeeById will be created when your view model is created, so employeeId.value is still null.
Then, because of SharingStarted.WhileSubscribed(). the map function will only get called when your flow has a subscriber on your repeatOnLifecycle(Lifecycle.State.STARTED). At this time, your employeeId.value is set the correct value. This is why you get a very weird log.
To fix your issue, I think some things need to be changed.
Your DAO
@Query("SELECT * FROM employees WHERE id = :id")
fun getEmployeeById(id: Int): Flow<EmployeeModel?>
Your viewModel. I assume that you have a state flow for your employee. You should use flatMap to update your employeeById value whenever your employee changes.
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)
Last thing, if you use employeeById to display data. Consider using StateFlow instead of SharedFlow
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论