4

我有一个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 替换上述场景?
4

2 回答 2

4

如果您未能将映射的冷流转换为热流,它会在您每次收集它时重新启动该流(例如重新创建您的 Activity 时)。这就是冷流的工作原理。

我有一种感觉,他们将充实 StateFlow/SharedFlow 的转换函数,因为将它们映射到冷流并且必须将它们转回热流感觉非常尴尬。

如果您不想手动清晰地映射第一个元素,则公共 Flow 必须是 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, SharingStarted.Eagerly, convertSortOrder("year"))
于 2021-01-09T18:13:50.227 回答
0

从片段/活动的角度来看,您必须创建一个收集流程的作业onStart()并取消它onStop()。即使在后台,使用lifecycleScope.launchWhenStarted也会使流程保持活跃。

使用bindin库轻松迁移到Flow。我有偏见,呵呵。

请参阅有关它的媒体文章

于 2021-03-13T12:29:56.773 回答