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

180 阅读2分钟

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

前言

在开发 Android 的时候,我们使用 MVVM 模式从 ViewModel 请求数据,并将结果转化成 UI。

数据请求是加载状态后,始终没有成功的使用方法,另外,UI 没有一种状态
跟踪方法,从创建到使用各种密封类的状态建模方法策略。

在以各种方式的同时,我想总结一下我对何时使用它们的方法以及它们的优点和优点的联系。

处理 UI 建模的方法有很多,但我们经常来讨论 4 种的建模模式。

  1. 创建多个状态并加载和错误另外
  2. 创建一个状态作为密封类并创建与状态一样多的实现
  3. 创建和管理一个数据状态类
  4. 创建一个状态数据类并分开加载和错误

示例场景

让假设一个场景,并通过上面我们的方式来实现它。假设通过网络请求获取到书本数据,需要将结果信息展示到UI界面上,如有错误需要特殊展示。

方案一

创建多个状态并将 Loading 和 Error 分开

ViewModel

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

    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()

    private val _name: MutableStateFlow<String> = MutableStateFlow("")
    val name: StateFlow<String> = _name.asStateFlow()

    private val _price: MutableStateFlow<String> = MutableStateFlow("")
    val price: StateFlow<String> = _price.asStateFlow()

    init {
        viewModelScope.launch {
            _loading.value = true
            val response = repository.getBookInfo()
            response
                .onSuccess { bookInfo ->
                    _loading.value = false
                    _error.value = false
                    _name.value = bookInfo.name
                    _price.value = bookInfo.price
                }
                .onFailure {
                    _loading.value = false
                    _error.value = true
                }
        }
    }
}

Activity

@AndroidEntryPoint
class ProgramOneActivity : BindActivity() {

    private val viewModel: ProgramOneViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 书名展示
        lifecycleScope.launch {
            viewModel.name.collect { name ->
                binding.tvName.text = name
            }
        }
         // 价格展示
        lifecycleScope.launch {
            viewModel.price.collect { price ->
                binding.tvPrice.text = price
            }
        }

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

优点

  • 通过单独定义状态,只能更改所需的数据。
  • 各状态之间互不影响。
  • 易于编写数据绑定代码

缺点

  • 状态很多,容易出错。
  • 很难预测状态将如何变化。
  • 处理订阅的代码很多,而且很复杂。

使用场景

  • 适用于简单屏幕
  • 在 1:1 结构中使用状态和数据绑定时。

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