uiState 未按预期更新

问题描述 投票:0回答:1

每当我触发“FavoritePost”或“DeletePost”并且uiState选择了TAB_TWO(收藏夹)时,它要么交换到TAB_ONE,保留在TAB_TWO中,但显示所有帖子而不仅仅是最喜欢的帖子,或者只是正常工作。

这是该屏幕的 ViewModel:

@HiltViewModel
class MainViewModel @Inject constructor(
    private val repo: MainRepository
) : ViewModelTemplate<MainState, MainScreenEvents>(MainState()) {

    init {
        initState()
    }

    override fun initState() {
        d("MainViewModel", "Initialized posts")
        viewModelScope.launch {
            repo.getPosts()
                .distinctUntilChanged()
                .collectLatest {
                    _uiState.emit(
                        _uiState.value.copy(posts = it)
                    )
                }
        }
    }

    override fun onEvent(event: MainScreenEvents) {
        when (event) {
            is ChangeTab -> {
                viewModelScope.launch {
                    d("MainViewModel", "Changing to ${event.tabNumber}")
                    when (event.tabNumber) {
                        TAB_ONE -> repo.getPosts()
                        TAB_TWO -> repo.getFavoritedPosts()
                    }.distinctUntilChanged()
                        .collect {
                        _uiState.emit(
                            _uiState.value.copy(
                                selectedTab = event.tabNumber,
                                posts = it
                            )
                        )
                    }
                }
            }

            is DeletePost -> {
                viewModelScope.launch {
                    repo.setDeletedPost(event.post)
                    if (event.post.isFavorited)
                        repo.setFavoritePost(event.post)
                }
            }

            is FavoritePost -> {
                viewModelScope.launch {
                    repo.setFavoritePost(event.post)
                }
            }
        }
    }
}

视图模型模板:

abstract class ViewModelTemplate<T : States, in R : Events>(initialState: T) : ViewModel() {

    protected val _uiState: MutableStateFlow<T> = MutableStateFlow(initialState)
    val uiState: StateFlow<T> = _uiState

    protected open fun initState() {
        d("viewmodel", "I did nothing!")
    }

    abstract fun onEvent(event: R)
}

活动类:

sealed class Events {
    sealed class MainScreenEvents : Events() {
        data class FavoritePost(val post: PostsEntity) : MainScreenEvents()
        data class DeletePost(val post: PostsEntity) : MainScreenEvents()
        data class ChangeTab(val tabNumber: MainScreenTabId) : MainScreenEvents()
    }

    sealed class DeletedPostsScreenEvents : Events() {
        data class CheckPost(val post: DeletedPosts) : DeletedPostsScreenEvents()
        data object RestorePosts : DeletedPostsScreenEvents()
        data object RestoreAllPosts : DeletedPostsScreenEvents()
    }

    sealed class PostScreenEvents : Events() {
        data class PostEntity(val title: String, val body: String) : PostScreenEvents()
    }
}

标签:

enum class MainScreenTabId(val text: String, val icon: ImageVector) {
    TAB_ONE("Home", Default.Home),
    TAB_TWO("Favorite", Default.Favorite)
}

州:

sealed class States {
    data class MainState(
        val posts: List<PostsEntity> = emptyList(),
        val selectedTab: MainScreenTabId = TAB_ONE
    ) : States()

    data class DeletedPostsState(
        val posts: List<DeletedPosts> = emptyList()
    ) : States()

    data object EmptyState : States()
}

存储库:

class MainRepository @Inject constructor(
    private val postsService: PostsServiceImplementation,
    private val postsDao: PostsDao
) {
    init {
        CoroutineScope(IO).launch {
            postsDao.updateDbFromClient(
                postsService.getPosts().map {
                    it.toEntity()
                })
        }
    }

    fun getPosts(): Flow<List<PostsEntity>> {
        return postsDao.getAvailablePosts()
    }

    fun getFavoritedPosts(): Flow<List<PostsEntity>> {
        return postsDao.getFavoritedPosts()
    }

    fun getDeletedPosts(): Flow<List<PostsEntity>> {
        return postsDao.getDeletedPosts()
    }

    suspend fun setFavoritePost(post: PostsEntity) {
        postsDao.updatePost(post.copy(isFavorited = !post.isFavorited))
    }

    suspend fun setDeletedPost(post: PostsEntity) {
        postsDao.updatePost(post.copy(isDeleted = !post.isDeleted))
    }

    suspend fun createPosts(postRequest: PostRequest): PostResponse? {
        return postsService.createPosts(postRequest)
    }
}

如果有帮助,我会使用 RoomDB,但我真的认为问题在于我如何处理 ViewModel 内的 Flow。

如果您对我的代码有什么需要补充的,请补充,我想学习!

我可以保证问题不在于我如何处理可组合项中的事件。

尝试将 StateFlow 处理集中在单个函数中(没有改变任何内容)

干杯!

android kotlin android-viewmodel kotlin-flow kotlin-stateflow
1个回答
0
投票

您不应该在视图模型中收集流,它们只应该被转换并转换为 StateFlow,然后在您的可组合项中收集。

_uiState
中移除
uiState
ViewModelTemplate
,并通过以下方式替换
init
中的
initState
块和
MainViewModel

private val currentTab: MutableStateFlow<MainScreenTabId> = MutableStateFlow(TAB_ONE)

val uiState: StateFlow<MainState> = currentTab
    .flatMapLatest {
        when (it) {
            TAB_ONE -> repo.getPosts()
            TAB_TWO -> repo.getFavoritedPosts()
        }
    }
    .combine(currentTab, ::MainState)
    .stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5_000),
        initialValue = MainState(),
    )

基础是当前选项卡,它包含在流中,因此其他流操作可以基于它。首先发生的事情是根据当前选项卡将流程切换到正确的存储库流程。然后,流的内容与当前选项卡一起转换为 MainState 对象。然后该流被转换为 StateFlow,以便 UI 可以轻松收集。

切换选项卡时,唯一要做的就是设置

currentTab
,StateFlow(和 UI)就会相应更新。您只需将
ChangeTab
中的
onEvent
分支简化为:

is ChangeTab -> {
    currentTab.value = event.tabNumber
}
© www.soinside.com 2019 - 2024. All rights reserved.