问题描述
我有一个名为 LiveData
的 sortOrder
,然后还有另一个名为 myData
的变量,它观察 sortOrder
的任何变化并相应地填充数据。
class Testviewmodel @viewmodelInject constructor() : viewmodel() {
private val sortOrder = mutablelivedata<String>()
val myData = sortOrder.map {
Timber.d("Sort order changed to $it")
"Sort order is $it"
}
init {
sortOrder.value = "year"
}
}
在活动中观察
class TestActivity : AppCompatActivity() {
private val viewmodel: Testviewmodel by viewmodels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
// Observing data
viewmodel.myData.observe(this) {
Timber.d("Data is : $it")
}
}
}
问题
- 如何在不改变输出的情况下用
Flow/StateFlow
API 替换上述场景?
解决方法
如果您未能将映射的冷流转换为热流,它会在您每次收集流时重新启动流(例如重新创建您的活动时)。这就是冷流的工作原理。
我有一种感觉,他们将充实 StateFlow/SharedFlow 的转换函数,因为将它们映射到冷流并必须将它们转回热流感觉非常尴尬。
如果您不想手动明确地映射第一个元素,则公共流必须是 SharedFlow,因为 stateIn
函数要求您直接提供初始状态。
private val sortOrder = MutableStateFlow("year")
val myData = sortOrder.map {
Timber.d("Sort order changed to $it")
"Sort order is $it"
}.shareIn(viewModelScope,SharingStarted.Eagerly,1)
或者您可以创建一个单独的函数,在 map
和 stateIn
函数调用中调用。
private val sortOrder = MutableSharedFlow<String>()
private fun convertSortOrder(order: String): String {
Log.d("ViewModel","Sort order changed to $order")
return "Sort order is $order"
}
val myData = sortOrder.map {
convertSortOrder(it)
}.stateIn(viewModelScope,convertSortOrder("year"))
,
从片段/活动的角度来看,您必须创建一个作业来收集 onStart()
中的流并在 onStop()
中取消它。使用 lifecycleScope.launchWhenStarted
将保持流活跃,即使在后台。
使用 bindin 库轻松迁移到 Flow
。我有偏见,不过。