如何用 Flow 替换 LiveData

问题描述

我有一个名为 LiveDatasortOrder,然后还有另一个名为 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)

或者您可以创建一个单独的函数,在 mapstateIn 函数调用中调用。

    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。我有偏见,不过。

参见an article on medium