首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使仙女座StateFlow<Model>多态化?

如何使仙女座StateFlow<Model>多态化?
EN

Stack Overflow用户
提问于 2022-07-06 13:08:34
回答 1查看 89关注 0票数 0

我现在正处于这样的阶段:我希望将我的StateFlow<Model>()公开到普通的BaseViewModel()类中,以便在它上实现公共操作,而不会在其他ViewModels实现中重复它们。最后,我有了一个想法,但在构建PoC时,我遇到了一些限制。我的想法及其局限性如下,欢迎您对原产地问题的解决方案。

我将我的模型分成interface和一个具体的实现。

代码语言:javascript
复制
sealed interface Model {
    var isLoading: Boolean
    var errors: List<String>
    /**
     * @param obj Should has the same concrete type as concrete type of object which copy() it invokes
     * */
    fun copy(obj: Model): Model
}

data class DeputiesModel(
    override var isLoading: Boolean = false,
    override var errors: List<String> = emptyList<String>(),
    var deputies: List<Deputy> = emptyList()
) : Model {
    override fun copy(obj: Model): DeputiesModel {
        if (obj !is DeputiesModel)
            throw IllegalArgumentException("Passed object implements ${Model::javaClass.name}" +
                    " interface, but should be concrete ${DeputiesModel::javaClass::name} implementation.")
        return this.copy(deputies = obj.deputies, isLoading = obj.isLoading, errors = obj.errors)
    }
}

我需要一个copy()方法,在接口data class copy()是关闭的重载和覆盖。

我的StateFlow实现已在BaseViewModel()中移动

代码语言:javascript
复制
abstract class BaseViewModel<T : Model> : ViewModel() {

    protected lateinit var state: MutableStateFlow<T>
    lateinit var uiState: StateFlow<T>

}

我在这里添加了泛型,以避免将Model类型转换为它的具体实现之一,例如,在继承BaseViewModel的类中使用DeputiesModel,否则这些额外的代码将使公开通用方法成为多余。

以下是第一种常见的方法:

代码语言:javascript
复制
fun removeShownError() {
    state.update { state ->
        state.errors = state.errors.filter { str -> !str.equals(state.errors.first()) }
        state.copy(state) as T
    }
}

该设计与实现的局限性在于,当原始参数化state.copy(state)进行uiState.collectLatest{}调用时,state.copy(isLoading = false)不触发state.copy(isLoading = false)调用。我还没找到根本原因。

代码语言:javascript
复制
    val viewModel: DeputiesViewModel by viewModels { viewModelFactory }
    lifecycleScope.launch {
        viewModel.uiState.collectLatest { it ->
            if (it.errors.isNotEmpty()) {
                showError(
                    view = requireActivity().findViewById(R.id.nav_view),
                    text = it.errors.first(),
                    onDismiss = { viewModel.removeShownError() }
                )
            }
            (binding.list.adapter as DeputiesAdapter).update(it.deputies)
        }
    }

就这样。你的想法很受欢迎。

EN

回答 1

Stack Overflow用户

发布于 2022-07-07 20:18:04

下面是如何用扩展函数来解决公共函数removeShownError()的示例,这样就不需要BaseViewModel了。

没有可变性的模型类:

代码语言:javascript
复制
sealed interface Model {
    val isLoading: Boolean
    val errors: List<String>
}

data class DeputiesModel(
    override val isLoading: Boolean = false,
    override val errors: List<String> = emptyList<String>(),
    val deputies: List<Deputy> = emptyList()
) : Model 

用于共享功能的扩展函数,在顶层定义:

代码语言:javascript
复制
// Since this is a sealed interface, you can create a single extension function to
// implement clearing errors for each of the implementations. This will be cleaner
// than having to deal with wrong input type problem in your current copy function
// implementation.
@Suppress("UNCHECKED_CAST")
fun <T: Model> T.withNewErrors(newErrors: List<String>): T = when (this) {
    is DeputiesModel -> copy(errors = newErrors)
    //... other types
} as T

fun <T: Model> MutableStateFlow<T>.removeShownError() {
    update { state ->
        state.withNewErrors(
            state.errors.filter { str -> !str.equals(state.errors.first()) }
        )
    }
}

现在不需要BaseViewModel了。您只需向具有相关流的任何ViewModel添加:

代码语言:javascript
复制
fun removeShownError() = state.removeShownError()

顺便说一句,在lateinit中使用ViewModel没有多大意义。这是像活动这样的类所需要的黑客,在这些类中,大多数初始化变量所需的操作都需要上下文,但是在类实例化时,上下文还没有准备好,而且create()是您自己的任何属性将被用于任何东西的最早点。在ViewModel中,您可能需要使用的所有东西都可以通过构造函数在类初始化时使用,因此没有理由推迟属性的初始化。

即使您必须为此使用lateinit,也没有必要将其用于它的合作伙伴不可变的公共属性,因为该属性可以只使用自定义getter,因此它首先没有要初始化的支持变量:

代码语言:javascript
复制
val uiState: StateFlow<T> get() = state
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72884134

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档