嘿,我正在学习 kotlin 中的流程。我正在学习MutableStateFlow和MutableSharedFlow。我尝试在现实世界的例子中学习MutableStateFlow。但我无法获得MutableSharedFlow示例,它更适合。我尝试了一些MutableStateFlow
例如,当我们从 api 获取数据时,我们可以使用 seal 类来进行相应的填充。
LoggedState.kt
sealed class LoggedState {
data class OnSuccess(val data: List<XYZ>) : LoggedState()
object OnEmpty : LoggedState()
data class IsLoading(val isLoading: Boolean = true) : LoggedState()
data class OnError(val message: String) : LoggedState()
}
Run Code Online (Sandbox Code Playgroud)
设置ViewModel.kt
class SettingsViewModel : ViewModel() {
var loggedMutableStateFlow = MutableStateFlow<LoggedState>(LoggedState.OnEmpty)
fun fetchData(){
val result = dataRepository.getLogged()
result.handleResult(
onSuccess = { response ->
val data = response?.items
if (!data.isNullOrEmpty()) {
loggedMutableStateFlow.value …Run Code Online (Sandbox Code Playgroud) android kotlin kotlin-flow kotlin-stateflow kotlin-sharedflow
\n\n\n由于launchWhenStarted和repeatOnLifecycle(STARTED)提供完全不同的功能(launchWhenStarted暂停协程的执行,而repeatOnLifecycle取消并重新启动新的协程),如果新API的名称相似(例如,使用launchWhenever作为重新启动的API) ,开发人员可能会感到困惑,甚至在没有注意到的情况下互换使用它们。
\n
什么时候使用哪个更简单的解释是什么?
\n我正在尝试遵循官方指南,根据以下文章,使用 Compose 从 LiveData 迁移到 Flow/StateFlow:
\n\n从 LiveData 迁移到 Kotlin\xe2\x80\x99s 流程
\n我尝试遵循第一篇文章末尾处的 Jetpack Compose 中的安全流集合中的建议。
\n\n\n在 Compose 中,副作用必须在受控环境中执行。\n 为此,请使用 LaunchedEffect 创建一个遵循可组合\xe2\x80\x99s 生命周期的协程。在其块中,如果您需要在主机生命周期处于某种状态时重新启动代码块,则可以调用\nsuspend Lifecycle.repeatOnLifecycle。
\n
我设法以这种方式使用.flowWithLifecycle()来确保当应用程序转到后台时流不会发出:
\n@Composable\nfun MyScreen() {\n\n val lifecycleOwner = LocalLifecycleOwner.current\n\n val someState = remember(viewModel.someFlow, lifecycleOwner) {\n viewModel.someFlow\n .flowWithLifecycle(lifecycleOwner.lifecycle, Lifecycle.State.STARTED)\n .stateIn(\n scope = viewModel.viewModelScope,\n started = SharingStarted.WhileSubscribed(5000),\n initialValue = null\n )\n }.collectAsState()\n\n}\nRun Code Online (Sandbox Code Playgroud)\n我发现这非常“样板”——一定有更好的东西。我想在 ViewModel 中使用 StateFlow,而不是在 @Composable 中转换为 StateFLow 的 Flow,并使用.repeatOnLifeCycle(),这样我就可以使用多个.collectAsState() …
android kotlin kotlin-coroutines android-jetpack-compose kotlin-flow
最近作为 Kotlin 协程的一部分引入了该类StateFlow。
我目前正在尝试它并在尝试对我的 ViewModel 进行单元测试时遇到问题。我想要实现的目标:测试我StateFlow是否在 ViewModel 中以正确的顺序接收所有状态值。
我的代码如下:
视图模型:
class WalletViewModel(private val getUserWallets: GetUersWallets) : ViewModel() {
val userWallet: StateFlow<State<UserWallets>> get() = _userWallets
private val _userWallets: MutableStateFlow<State<UserWallets>> =
MutableStateFlow(State.Init)
fun getUserWallets() {
viewModelScope.launch {
getUserWallets.getUserWallets()
.onStart { _userWallets.value = State.Loading }
.collect { _userWallets.value = it }
}
}
Run Code Online (Sandbox Code Playgroud)
我的测试:
@Test
fun `observe user wallets ok`() = runBlockingTest {
Mockito.`when`(api.getAssetWallets()).thenReturn(TestUtils.getAssetsWalletResponseOk())
Mockito.`when`(api.getFiatWallets()).thenReturn(TestUtils.getFiatWalletResponseOk())
viewModel.getUserWallets()
val res = arrayListOf<State<UserWallets>>()
viewModel.userWallet.toList(res) //doesn't works
Assertions.assertThat(viewModel.userWallet.value is State.Success).isTrue() //works, …Run Code Online (Sandbox Code Playgroud) android kotlin android-viewmodel kotlin-coroutines kotlin-flow
正如我在标题中提到的,我很好奇两者之间的一般差异。你能帮忙吗?我找不到具体的区别,因为互联网上有复杂的例子。
android kotlin android-livedata kotlin-flow kotlin-stateflow
MutableSharedFlow 有 3 个参数:replay、extraBufferCapacity 和 onBufferOverflow。replay 和 extraBufferCapacity 有什么区别?
该文档提到以下内容:
replay - 重播给新订阅者的值的数量(不能为负数,默认为零)。
extraBufferCapacity - 除了重放之外缓冲的值的数量。当还有剩余缓冲区空间时,emit 不会暂停(可选,不能为负数,默认为零)。
我不明白两者之间的区别以及何时需要 extraBufferCapacity > 0。 extraBufferCapacity 只是发射器的额外重播能力吗?
android kotlin kotlin-coroutines kotlin-flow kotlin-sharedflow
如何收集activity中的两个状态流?因为我只消耗了第一个流量。
例如,viewmodel内部是这样的:
class ExampleViewModel: ViewModel(){
private val state = MutableStateFlow<HomeMainFragmentState>(HomeMainFragmentState.Init)
private val products = MutableStateFlow<List<ProductEntity>>(mutableListOf())
//to be consumed
fun getState() : StateFlow<HomeMainFragmentState> = state
fun getProducts() : StateFlow<List<ProductEntity>> = products
}
Run Code Online (Sandbox Code Playgroud)
然后在我看来是这样的:
private fun observe(){
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED){
viewModel.getState().collect { state -> handleState(state) }
viewModel.getProducts().collect{ products -> handleProducts(products) }
}
}
}
Run Code Online (Sandbox Code Playgroud)
问题是,只有第一个流被消耗,因为这种情况是“状态”,产品从未被活动/片段消耗/执行。
如何解决这个问题?我还阅读了有关组合流程的信息,这是否意味着第二个流程取决于第一个流程的运行?
我最喜欢在 Android 上执行网络请求的方法(使用 Retrofit)。它看起来像这样:
// NetworkApi.kt
interface NetworkApi {
@GET("users")
suspend fun getUsers(): List<User>
}
Run Code Online (Sandbox Code Playgroud)
在我的 ViewModel 中:
// MyViewModel.kt
class MyViewModel(private val networkApi: NetworkApi): ViewModel() {
val usersLiveData = flow {
emit(networkApi.getUsers())
}.asLiveData()
}
Run Code Online (Sandbox Code Playgroud)
最后,在我的活动/片段中:
//MyActivity.kt
class MyActivity: AppCompatActivity() {
private viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.usersLiveData.observe(this) {
// Update the UI here
}
}
}
Run Code Online (Sandbox Code Playgroud)
我喜欢这种方式的原因是因为它本身就可以与 Kotlin flow 配合使用,非常易于使用,并且有很多有用的操作(flatMap 等)。
但是,我不确定如何使用此方法优雅地处理网络错误。我能想到的一种方法是用作Response<T>网络 API 的返回类型,如下所示:
// NetworkApi.kt
interface NetworkApi {
@GET("users")
suspend …Run Code Online (Sandbox Code Playgroud) 我最近开始在 Android 中使用 Flows。我读到 Flows 很冷 StateFlows 很热,那么为什么我们应该更喜欢使用 StateFlows for Android 而不是 Flows 呢?使用 Flows 不是更好吗,因为当应用程序进入后台时它们会停止生产者?在 Android 开发中是否存在应该使用 Flows 而不是 Stateflow 的场景?
我的应用程序中有一个 UserStateModel(数据类)类型的 StateFlow。
private val _userStateFlow: MutableStateFlow<UserStateModel?> = MutableStateFlow(UserStateModel())
val userStateFlow: StateFlow<UserStateModel?> = _userStateFlow
Run Code Online (Sandbox Code Playgroud)
这是用户状态模型
data class UserStateModel(
val uid: String? = null,
val username: String? = null,
val profileImageUrl: String? = null,
var isLoggedIn: Boolean = false,
val isPremiumUser: Boolean = false,
val posts: List<Post>? = listOf()
)
Run Code Online (Sandbox Code Playgroud)
当我使用新的用户名更新 StateFlow 时,它会将更改发送给收集器并更新 UI。但是当我更改帖子内的属性时:列表?列表它不会发出更改。当我更改列表的大小时,它会更改,而当我更改索引 0 处的帖子的 name 属性时,它不会更改。如何检测 Data 类的子属性的更改?
现在我使用一个丑陋的解决方法,我补充道
val updateErrorWorkaround: Int = 0
Run Code Online (Sandbox Code Playgroud)
到 UserStateModel 数据类并将其加一以便收集器收到通知
PS我正在使用 MVVM + Clean Architecture 和 Jeptack Compose
编辑 这是我的帖子模型:
data class …Run Code Online (Sandbox Code Playgroud) android kotlin kotlin-coroutines android-jetpack-compose kotlin-flow