Kav*_*u S 7 android kotlin android-livedata kotlin-flow
我们知道LiveData 具有生命周期感知能力,如果配置发生更改,LiveData 对象不会每次都从数据库(本地/远程)重新查询,并且仅当数据有任何更新时才会更新。
最近我开始使用Kotlin Flow,我应该承认它最适合数据层,即在存储库中实现,以便通知 ViewModel。但我也在 ViewModel/View 层中使用了Kotlin Flow,以便直接根据其状态collect(密封类实现)来确定Fragment 中的 Flow 对象。我在使用 Flow 时遇到的问题是每次配置更改时都会从数据库(本地/远程)检索数据。
这种情况应该怎么办?有没有办法在使用 Flow 时避免重新查询,或者我应该只在 ViewModel/View 层中使用 LiveData?
示例代码
sealed class Status<T> {
class Processing<T> : Status<T>()
data class Completed<T>(val value: T) : Status<T>()
data class Error<T>(val error: String) : Status<T>()
companion object {
fun <T> processing() = Processing<T>()
fun <T> completed(value: T) = Completed(value)
fun <T> error(error: String) = Error<T>(error)
}
}
Run Code Online (Sandbox Code Playgroud)
回购协议:
class Repo(database: LocalDatabase){
fun retrieveUsersData() = flow<Status<List<Users>>>{
emit(Status.processing())
database.dao.getUsers().collect{
// Assume db queries successfully and returns list of users
emit(Status.completed(it))
}
}.catch {
emit(Status.error(it.error.toString()))
}.flowOn(Dispatchers.IO)
}
Run Code Online (Sandbox Code Playgroud)
视图模型:
class MyViewModel(application: Application): AndroidViewModel(application)
{
private val db = LocalDatabase.getInstance(application)
private val repo = Repo(db)
val usersData= repo.retrieveUsersData(dataCollectionType)
}
Run Code Online (Sandbox Code Playgroud)
分段:
class UsersFragment: Fragment(){
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Assume all the declarations are done properly
coroutineScope.launch {
retrieveUsersData()
}
}
private suspend fun retrieveUsersData(){
viewModel.retrieveUsersData().collect{ status ->
// Based on the Status do the actions.
// When Status is Completed set the data to the adapter.
}
}
} // end of Fragment
Run Code Online (Sandbox Code Playgroud)
实际上有一个asLiveData()将 Flow 转换为 LiveData 的方法。您可以将其附加viewModelScope.coroutineContext到 Flow,以便 Flow 将尊重 ViewModel 的生命周期。这是基于您的代码的示例。
class MyViewModel(application: Application): AndroidViewModel(application)
{
private val db = LocalDatabase.getInstance(application)
private val repo = Repo(db)
val usersData = repo.retrieveUsersData(dataCollectionType).asLiveData(viewModelScope.coroutineContext)
}
Run Code Online (Sandbox Code Playgroud)
然后,像往常一样在您的视图(活动/片段)中观察此 LiveData。当 ViewModel 被销毁时,该 Flow(转换为 LiveData)也将被销毁。
viewModel.userData.observe(viewLifecycleOwner, { status ->
// Based on the Status do the actions.
// When Status is Completed set the data to the adapter.
}
Run Code Online (Sandbox Code Playgroud)
为了获得最佳实践,
据我所知,如果不包装视图模型中的流,就无法做到这一点。在您的示例中,ViewModel 不保留真实状态,而只是转发流,因此您不会从配置更改中幸存下来获得任何好处。
针对您的用例的建议架构是将流映射到视图模型内的 liveData。m0skit0 参考链接 ( https://www.youtube.com/watch?v=B8ppnjGPAGE )中的视频显示了 lifeData 构建器的用法。
在你的情况下,这将很简单:
class MyViewModel(application: Application): AndroidViewModel(application)
{
private val db = LocalDatabase.getInstance(application)
private val repo = Repo(db)
val usersData = liveData {
emit(repo.retrieveUsersData(dataCollectionType))
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5120 次 |
| 最近记录: |