为了活动小家电-UI状态管理(二)

125 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

为了活动小家电,接着上篇搞!

方案二

创建一个具有密封类的状态并创建与状态数量一样多的实现

ViewModel

@HiltViewModel
class ProgramTwoViewModel @Inject constructor(
    private val repository: LibraryRepository
) : ViewModel() {

    sealed class State {

        data class Success(
            val name: String,
            val price: String
        ) : State()

        object Empty : State()

        object Failure : State()

        object Loading : State()
    }

    private val _state: MutableStateFlow<State> = MutableStateFlow(State.Loading)
    val state: StateFlow<State> = _state.asStateFlow()


    init {
        viewModelScope.launch {
            _state.value = State.Loading
            val response = repository.getBookInfo()
            response
                .onSuccess { bookInfo ->
                    val (name, price) = (bookInfo.name to bookInfo.price)
                    if (name.isEmpty() && price.isEmpty()) {
                        _state.value = State.Empty
                    } else {
                        _state.value = State.Success(bookInfo.name, bookInfo.price)
                    }
                }
                .onFailure {
                    _state.value = State.Failure
                }
        }
    }
}

Activity

@AndroidEntryPoint
class ProgramTwoActivity : BindActivity() {
    private val viewModel: ProgramTwoViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        lifecycleScope.launch {
            viewModel.state.collect { state ->
                // 加载中展示
                binding.ivLoading.isVisible = state is State.Loading
                // 加载异常展示
                binding.ivError.isVisible = state is State.Failure
                // 信息展示
                if (state is State.Success) {
                    binding.tvName.text = state.name
                    binding.tvPrice.text = state.price
                }
            }
        }
    }
}

优点

  • 通过实现类似于 MVI 的形式,可以清楚地表达 UI 的意图。
  • 通过利用密封类,有利于面向对象的处理。
  • 改变 UI 的代码没有分散相对比较集中,都是统一返回的,所以代码分析很方便。
  • 由于它只有一种状态,因此没有必要考虑状态的混合。

缺点

  • 因为要表达的状态要列出来,所以当画面相对复杂之后,代码的复杂度急剧增加,无法进行局部更新。
  • 随着每个状态的变化,恢复前一个状态的数据相对较困难,除非单独针对性的保留旧状态。
  • 共同状态更难表达,更难以分享。
  • 使用数据绑定非常困难。

使用场景

  • 以明确的意图表达 UI 时(意图可以直接更改为状态)
  • 加载或错误时可以视为完整状态
  • 不需要部分数据修改或先前状态时

为了活动小家电,下篇继续搞