首页 > 解决方案 > 如何处理android MVI架构中的多个API调用(单向数据流)?

问题描述

所以我正在关注 MVI 架构以及如何处理多个 api 调用结果,所以我的代码如下所示,我使用https://github.com/RohitSurwase/AAC-MVI-Architecture作为参考

模态.kt


data class HomeViewState(val postListState: PostListState)

sealed class PostListState {
    object Loading : PostListState()
    data class Success(val postList: List<Post>) : PostListState()
    data class Error(val message: String) : PostListState()
}

ViewModal.kt

private fun fetchPostFeed() {
    composite.add(postUseCase.fetchPostList().subscribe(
        { postList ->
            viewState = viewState.copy(postListState = PostListState.Success(postList))
        },
        { error ->
            viewState = viewState.copy(
                postListState = PostListState.Error(
                    message = error.localizedMessage ?: "Something went wrong while fetching postlist!!!"
                )
            )
            Timber.e(error)
        }
    ))
}

片段.kt

override fun renderViewState(viewState: HomeViewState) {
    when (viewState.postListState) {
        PostListState.Loading -> loadPosts()
        is PostListState.Success -> showPostListToUI(viewState.postListState.postList)
        is PostListState.Error -> showErrorLayout(viewState.postListState.message)
    }
}

所以流程是当 ViewModel 初始化默认状态设置为PostListState.Loading时,这个状态更改片段的renderViewState()被调用,它发出加载事件,由fetchPostFeed()中的视图模型处理,以防万一成功或错误。

问题

现在我也想进行 API 调用来加载评论,所以我尝试将实现更改为类似

模态.kt

data class HomeViewState(val postListState: PostListState, val commentsState: CommentsState)

sealed class PostListState {
    object Loading : PostListState()
    data class Success(val postList: PagedList<Post>) : PostListState()
    data class Error(val message: String) : PostListState()
}

sealed class CommentsState {
    object Loading : CommentsState()
    data class Success(val commList: List<Comments>) : CommentsState()
    data class Error(val message: String) : CommentsState()
}

在片段中,我们将

片段.kt

override fun renderViewState(viewState: HomeViewState) {
    when (viewState.postListState) {
        PostListState.Loading -> loadPosts()
        is PostListState.Success -> showPostListToUI(viewState.postListState.postList)
        is PostListState.Error -> showErrorLayout(viewState.postListState.message)
    }

    when (viewState.commentsState) {
        CommentsState.Loading -> loadComments()
        is CommentsState.Success -> showCOmments(viewState.commentsState.commList)
        is CommentsState.Error -> showErrorLayout(viewState.commentsState.message)
    }
}

现在的事情是假设 post fetch 较早完成并且状态更新为PostListState.Success并且如果评论状态仍处于CommentsState.Loading它将重新触发评论的加载,这是不希望的。如何处理多个 api 调用,以便更改一个 API 调用的状态不会重新触发其他 api 调用中的事件

标签: androidkotlin

解决方案


对于这种情况,我会将这两个调用与以下内容结合起来:

sealed class PostListState {
    object Loading : PostListState()
    data class Success(val postList: List<Post>, val commList: List<Comments>) : PostListState()
    data class Error(val message: String) : PostListState()
}

这里的名称“PostList”将代表帖子列表及其评论,您可以将其更改为包含两者的内容。

例如,在 fetchPostFeed 中,您可以同时调用两个端点,或者一个接一个地等待两者返回结果并将它们分别发布到成功响应中,如“postList”和“commList”。另一种选择是使用映射器将它们组合在一个新的数据类中(即一个帖子列表,每个帖子都有各自的评论列表)。

例如,使用 RxJava 会是这样的:

Observable.zip(
            FetchPostList().subscribeOn(Schedulers.io()),
            FetchCommentList().subscribeOn(Schedulers.io()),
            BiFunction { firstResponse: PostList,
                         secondResponse: CommentList ->
                Pair(firstResponse, secondResponse)
            })
            .flatMap { resultPair ->
                Observable.just(PostListState.Success(resultPair.first, resultPair.second))
            }
            .onErrorReturn(Error)
            .startWith(Loading)
            .observeOn(AndroidSchedulers.mainThread())

推荐阅读