class FriendViewModel : ViewModel() { //对内容器 private val _myContainer=RealContainer<FriendUiState,YsSingleEvent>(FriendUiState(),viewModelScope) //对外容器 val myContainer:Container<FriendUiState,YsSingleEvent> = _myContainer }
为了进一步封装和屏蔽容器类的构造细节,我们参考viewModel在kotlin中的使用方法,实现一套委任模式。给ViewModel添加一个扩展函数containers(),然后返回Lazy对象,这样实现了懒加载和函数封装的功能。
/** * 构建viewModel的Ui容器,存储Ui状态和一次性事件 */ fun <STATE : UiState, SINGLE_EVENT : UiSingleEvent> ViewModel.containers( initialState: STATE, ): Lazy<MutableContainer<STATE, SINGLE_EVENT>> { return ContainerLazy(initialState, viewModelScope) } class ContainerLazy<STATE : UiState, SINGLE_EVENT : UiSingleEvent>( initialState: STATE, parentScope: CoroutineScope ) : Lazy<MutableContainer<STATE, SINGLE_EVENT>> { private var cached: MutableContainer<STATE, SINGLE_EVENT>? = null override val value: MutableContainer<STATE, SINGLE_EVENT> = cached ?: RealContainer<STATE, SINGLE_EVENT>(initialState, parentScope).also { cached = it } override fun isInitialized() = cached != null }
使用了扩展方法+委任模式后的代码,代码减少了许多,同时屏蔽了容器的构造参数细节。
class FriendViewModel @Inject constructor( private val friendRepository: FriendRepository, ) : ViewModel() { //定义UI状态 data class FriendUiState( //朋友列表 val friendBeanList: List<FriendBean> = emptyList(), //是否刷新中 val refreshing: Boolean = false, //是否加载更多 val loadMore: Boolean = false, //是否还有更多数据 val noMoreData: Boolean = false, ) : UiState //定义一次性事件 sealed class FriendSingleEvent : UiSingleEvent { class ToastEvent(val message: String, val short: Boolean = false) : FriendSingleEvent() } //对内容器 private val _container by containers<FriendUiState, FriendSingleEvent>(FriendUiState()) //对外容器 val container: Container<FriendUiState, FriendSingleEvent> = _container
现在,我们已经可以直接在viewModel中对状态流和事件流进行操作
//更新状态 _container.updateState { copy( friendBeanList = //如果是刷新,则清空列表 if (refresh) data.list //如果不是刷新,则添加在列表的后面 else friendBeanList + data.list, //没有数据 noMoreData = data.list.isEmpty() ) } //发送事件 _container.sendEvent(FriendSingleEvent.ToastEvent(it))