Android开发中如何正确处理View State

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

目前我的应用程序中有这种方法:

ViewState(每个屏幕一个 viewState)

sealed class CategoriesViewState {
    object Loading : CategoriesViewState()

    data class Error(
        val errorMessage: String,
        val messageType: UIComponentType
    ) : CategoriesViewState()

    data class CategoryList(
        val categories: List<Category>
    ) : CategoriesViewState()
}

我使用实时数据在我的片段/活动中观察到这种状态:

  viewModel.viewState.observe(viewLifecycleOwner, Observer {
            when (it) {
                is CategoriesViewState.Loading -> {
                progress_bar.visibility = View.VISIBLE

                    Log.d(TAG, "LOADING")
                }

                is CategoriesViewState.Error -> {
                progress_bar.visibility = View.GONE

                    Log.d(TAG, "ERROR")

                }

                is CategoriesViewState.CategoryList -> {
                progress_bar.visibility = View.GONE

                    Log.d(TAG, "DATA")

                }
            }
        })

并且运行良好。

但是在我看来,随着应用程序的增长,效率很低。

假设我的应用程序中有 20 个屏幕:我需要 20 个 viewState,我需要在每个屏幕中编写相同的 when 语句,我需要在每个屏幕中编写这个丑陋的 Visible/Gone(不是为了提到我需要在每次调用中设置加载状态)

也许我完全错了,这是常见的方法,但对我来说,这似乎是大量的代码重复。

我没有具体的问题,我只是想知道这是否是 Android 开发中的常见方法,如果不是,我的代码中做错了什么?

android kotlin mvvm android-livedata android-architecture-components
2个回答
13
投票

关于不同活动的状态,您不需要每次创建新屏幕时都进行它。您可以按照以下方法并进行相应修改:

sealed class UIState<out T> where T : Any? {

    object Loading : UIState<Nothing>()

    data class Success<T>(val data: T) : UIState<T>()

    data class Failure(val errorMessage: String, val messageType: UIComponentType) : UIState<Nothing>()
}

所以,现在你的

CategoriesViewState
可以表示为
UiState<List<Category>>

我还创建了一些扩展函数,使观察变得更容易:

infix fun <T> UIState<T>.takeIfSuccess(onSuccess: UIState.Success<T>.() -> Unit): UIState<T> {
    return when (this) {
        is UIState.Success -> {
            onSuccess(this)
            this
        }
        else -> {
            this
        }
    }
}

infix fun <T> UIState<T>.takeIfError(onError: UIState.Failure.() -> Unit): UIState<T> {
    return when (this) {
        is UIState.Failure -> {
            onError(this)
            this
        }
        else -> {
            this
        }
    }
}

以及实时数据的观察方法:

viewModel.viewState.observe(viewLifecycleOwner) { state ->
    state takeIfSuccess {
        // Here's the success state
    } takeIfError {
        // Here's the error state
    }
}

编辑:

如果你不想最终写菱形括号(

<>
),这里是使用类型别名的方法;

// for UIState of UserData class you can do something like this,
typealias UserDataState = UIState<UserData>
...

// Then use this typealias where you should be writing UIState, I.e.
val userLiveData = MutableLiveData<UserDataState>(value)

0
投票

Jeel Vankhede 的回答很好。 我做一点小小的补充。 在 Android 中,我们必须存储 Fragment 的参数。 我通过单元测试发布了所有代码here

sealed class UiState<out A, out T> where A : Any?, T : Any? {

    object Empty : UiState<Nothing, Nothing>()

    data class Arguments<A>(val arg: A?) : UiState<A, Nothing>()

    data class Success<A, T>(val arg: A?, val data: T) : UiState<A, T>()

    data class Error(val message: String, val error: Throwable) : UiState<Nothing, Nothing>()

}
© www.soinside.com 2019 - 2024. All rights reserved.