英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论