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

138 阅读2分钟

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

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

方案四

分别创建单个状态数据类,Loading和Error

ViewModel

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

    data class State(
        val name: String = "",
        val price: String = ""
    ) {
        val isEmpty: Boolean = name.isEmpty() && price.isEmpty()
    }

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

    private val _loading: MutableStateFlow<Boolean> = MutableStateFlow(false)
    val loading: StateFlow<Boolean> = _loading.asStateFlow()

    private val _error: MutableStateFlow<Boolean> = MutableStateFlow(false)
    val error: StateFlow<Boolean> = _error.asStateFlow()

    init {
        viewModelScope.launch {
            _loading.value = true
           val response = repository.getBookInfo()

            response
                .onSuccess { bookInfo ->
                    _loading.value = false
                    _state.update { state ->
                        state.copy(
                            name = bookInfo.name,
                            price = bookInfo.price
                        )
                    }
                }
                .onFailure {
                    _loading.value = false
                    _error.value = true
                }
        }
    }
}

Activity

@AndroidEntryPoint
class ProgramFourActivity : BindActivity() {

    private val viewModel: ProgramFourViewModel by viewModels()

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

        // 书本信息展示
        lifecycleScope.launch {
            viewModel.state.collect { state ->
                binding.tvName.text = state.name
                binding.tvPrice.text = state.price
            }
        }
        
        // 加载异常展示
        lifecycleScope.launch {
            viewModel.error.collect { error ->
                binding.ivError.isVisible = error
            }
        }

        // 加载中展示
        lifecycleScope.launch {
            viewModel.loading.collect { loading ->
                binding.ivLoading.isVisible = loading
            }
        }
    }
}

优点

  • UI 状态不依赖于加载或错误,因此可以单独处理。
  • 使用 Base 时,它提供了可扩展的结构。
  • 通过单独定义状态,可以更好的更改所需的数据。

缺点

  • 如果 UI 状态依赖于加载或错误,则处理有些复杂。
  • 因为加载状态可以在几个地方改变,所以你需要小心改变状态。
  • 处理订阅的代码很多,而且很复杂。

使用场景

  • 将 UI 状态与加载和错误分开使用时
  • 如果您想在 Base 中处理一般的加载和错误

总结

你会使用什么 UI 策略?是否会从中选择一种方案呢?\

最后,考虑到团队成员的问题和约定,我认为这个问题没有完美的答案,团队实践比最佳实践更重要。但是我们需要根据自身研发的业务场景去选择一种更合适的方案,目的就是方便后期的扩展与维护。

我的问题

那么如何处理最近使用 LiveData 或 StateFlow 的状态?这是一个困扰许久的问题,有这样的需求我们一直都是用保存状态的形式做处理,但是始终觉得不太优雅。