1 MVI简述
2 架构演变
实验场景:实现一个简单页面
- 进入页面加载Loading
- 请求用户名和一个简单列表,列表数据有标题,内容和勾选。请求返回后更新UI用户名和列表数据并取消Loading
- 点击列表某一行时,反选勾选框
2.1 MVVM
// bean
data class UserNewsBean(
var title: String = "",
var content: String = "",
var isCheck: Boolean = false
)
// Model层
class UserPageRepository {
suspend fun getUserName(): String {
delay(1000)
return "xxx"
}
suspend fun requestUserNewsList(): List<UserNewsBean> {
delay(2000)
val dataList = mutableListOf<UserNewsBean>()
for (i in 0 until 20) {
dataList.add(UserNewsBean(
"title$i",
"content$i",
false
))
}
return dataList
}
}
// ViewModel层
class UserPageViewModel: BaseViewModel() {
// --model start--
private val _showLoading = MutableLiveData<Boolean>()
val showLoading: LiveData<Boolean> = _showLoading
private val _userName = MutableLiveData<String>()
val userName: LiveData<String> = _userName
private val _dataList = MutableLiveData<List<UserNewsBean>>()
val dataList: LiveData<List<UserNewsBean>> = _dataList
// --model end--
private val repository = UserPageRepository()
fun attach() {
viewModelScope.launch {
_showLoading.value = true
_userName.value = repository.getUserName()
_dataList.value = repository.requestUserNewsList()
_showLoading.value = false
}
}
fun onItemClick(position) {
val dataListTemp = _dataList.value
if (!dataListTemp.isNullOrEmpty && position in dataListTemp.indices) {
dataListTemp[position].isCheck = !dataListTemp[position].isCheck
_dataList.value = dataListTemp
}
}
}
// View层
class UserPage: BaseActivity() {
private val viewModel = createViewModel()
fun onCreate() {
viewModel.showLoading.observe(this) {
// progressBar show or hide
}
viewModel.userName.observe(this) {
// update userName
}
viewModel.dataList.observe(this) {
// update list
}
list.setOnItemClickListener { position ->
viewModel.onItemClick(position)
}
}
}
特点:数据从ViewModel单向流向了View层,页面事件从View层流向了ViewModel层
2.2 Flow
class UserPageViewModel: BaseViewModel() {
// --model start--
private val _showLoading = MutableStateFlow<Boolean>()
val showLoading: StateFlow<Boolean.Companion> = _showLoading.asStateFlow()
}
class UserPage: BaseActivity() {
fun onCreate() {
lifecycleScope.launch {
launch {
viewModel.showLoading.collect {
}
}
launch {
viewModel.userName.collect {
}
}
launch {
viewModel.dataList.collect {
}
}
}
}
}
2.3 MVI
3 踩坑
3.1 StateFlow更新list,第一次可以收到更新列表,但是后面list变更后通知收不到
private val _uiState:StateFlow<UserPageUiState>()
val uiState: StateFlow<UserPageUiState> = _uiState.asStateFlow()
//1.第一次变更,view可以收到通知并更新列表
dataList = requestNews()
_uiState.value = UserPageUiState(false, "name", dataList)
//2.第二次,收不到了,下面的方法都试了都不行,StateFlow在value变更时,会判断oldValue == newValue就啥都不干
_uiState.value.dataList[position].isCheck = !_uiState.value.dataList[position].isCheck
//_uiState.value = _uiState
//_uiState.value = UserPageUiState(false, "name", _uiState.value.dataList)
//_uiState.value = UserPageUiState(false, "name", new List addAll(_uiState.value.dataList))
//3.修改列表,使用复制的方式就可以了
val dataList = _uiState.value.dataList.toMutableList()
dataList[position] = dataList[position].copy(isCheck = !dataList[position].isCheck)
_uiState.value = _uiState.value.copy(dataList = dataList)
3.2 观察多个值变化时,collect只有第一个收到消息
// view层
lifycycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.apply {
this.map { it.showLoading }
.distinctUntilChanged()
.collect {
// do something
}
this.map { it.userName }
.distinctUntilChanged()
.collect {
// do something
}
this.map { it.dataList }
.distinctUntilChanged()
.collect {
// do something
}
}
}
}
因为collect是阻塞的,只有第一个showLoading变化了能接收到,所以需要新开协程去接收每个值的变化
// view层
lifycycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.apply {
launch {
this.map { it.showLoading }
.distinctUntilChanged()
.collect {
// do something
}
}
launch {
this.map { it.userName }
.distinctUntilChanged()
.collect {
// do something
}
}
launch {
this.map { it.dataList }
.distinctUntilChanged()
.collect {
// do something
}
}
}
}
}
后面加了个扩展方法
fun<T, R> StateFlow<T>.setObserver(coroutineContext: CoroutineContext, dataGet: (T) -> R, action: (R) -> Unit) {
coroutineContext.launch {
this@setObserver.map { dataGet.invoke(it) }
.distinctUntilChanged()
.collect {
action.invoke(it)
}
}
}
// view层
lifycycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.apply {
setObserver(this@repeatOnLifecycle, { this.value.showLoading }) {
// do something
}
setObserver(this@repeatOnLifecycle, { this.value.userName }) {
// do something
}
setObserver(this@repeatOnLifecycle, { this.value.dataList }) {
// do something
}
}
}
}
3.3 StateFlow连续发送多个状态时,中间几个状态丢失了
特性。。。