当前位置: 首页 > news >正文

宿州金融网站建设个人网站系统

宿州金融网站建设,个人网站系统,wordpress 采集微博,怎么自己做网站凑钱前言MVI架构为了解决MVVM在逻辑复杂时需要写多个LiveData(可变不可变)的问题,使用ViewState对State集中管理,只需要订阅一个 ViewState 便可获取页面的所有状态通过集中管理ViewState,只需对外暴露一个LiveData,解决了MVVM模式下LiveData膨胀…

前言

MVI架构为了解决MVVM在逻辑复杂时需要写多个LiveData(可变+不可变)的问题,使用ViewState对State集中管理,只需要订阅一个 ViewState 便可获取页面的所有状态

通过集中管理ViewState,只需对外暴露一个LiveData,解决了MVVM模式下LiveData膨胀的问题

但页面的所有状态都通过一个LiveData来管理,也带来了一个严重的问题,即页面不支持局部刷新

虽说如果是RecyclerView可以通过DifferUtil来解决,但毕竟不是所有页面都是通过RecyclerView写的,支持DifferUtil也有一定的开发成本

因此直接使用MVI架构会带来一定的性能损耗,相信这是很多人不愿意用MVI架构的原因之一

本文主要介绍如何通过监听LiveData的属性,来实现MVI架构下的局部刷新

Mavericks框架介绍

Mavericks框架是Airbnb开源的一个MVI框架,Mavericks基于Android Jetpack与Kotlin Coroutines,主要目标是使页面开发更高效,更容易,更有趣,目前已经在Airbnb的数百个页面上使用

下面我们来看下Mavericks是怎么使用的

// 1. 包含页面所有状态的data class
data class CounterState(val count: Int = 0) : MavericksState// 2.负责处理业务逻辑的ViewModel,易于单元测试
class CounterViewModel(initialState: CounterState) : MavericksViewModel<CounterState>(initialState) {// 通过setState更新页面状态fun incrementCount() = setState { copy(count = count + 1) }
}// 3. View层,必须实现MavericksView接口   
class CounterFragment : Fragment(R.layout.counter_fragment), MavericksView {private val viewModel: CounterViewModel by fragmentViewModel()override fun onViewCreated(view: View, savedInstanceState: Bundle?) {counterText.setOnClickListener {viewModel.incrementCount()}}//4. 页面刷新回调,每当状态刷新时会回调这里override fun invalidate() = withState(viewModel) { state ->counterText.text = "Count: ${state.count}"}
}

如上所示,看上去也很简单,主要包括几个模块

  1. 包括页面所有状态的Model层,其中的状态全都是不可变的,并且有默认值

  1. 负责处理业务逻辑的ViewModel,在其中通过setState来更新页面状态

  1. View层,必须实现MavericksView接口,每当状态刷新时都会回调invalidate函数,在这里渲染UI

可以看出,Mavericks中View层与Model层的交互,也并没有包装成Action,而是直接暴露的方法

上篇文章也的确有很多同学说使用Action交互比较麻烦,看起来Action这层的确可要可不要,Airbnb也没有使用,主要看个人开发习惯吧

支持局部刷新

上面介绍了Mavericks的简单使用,下面我们来看下Mavericks是怎么实现局部刷新的

data class UserState(val score: Int = 0,val previousHighScore: Int = 150,val livesLeft: Int = 99,
) : MavericksState {val pointsUntilHighScore = (previousHighScore - score).coerceAtLeast(0)val isHighScore = score >= previousHighScore
}class CounterFragment : Fragment(R.layout.counter_fragment), MavericksView {override fun onViewCreated(view: View, savedInstanceState: Bundle?) {//直接监听State的属性,并且支持设置监听模式  viewModel.onEach(UserState::pointsUntilHighScore,deliveryMode = uniqueOnly()) {//..}viewModel.onEach(UserState::score) { //...}    }
}
  1. 如上所示,Mavericks可以只监听State的其中一个属性来实现局部刷新,只有当这个属性发生变化时才触发回调

  1. onEach也可以设置监听模式,主要是为了防止数据倒灌,例如Toast这些只需要弹一次,页面重建时不应该恢复的状态,就适合使用uniqueOnly的监听模式

Mavericks实现属性监听的原理也很简单,我们一起来看下源码

fun <VM : MavericksViewModel<S>, S : MavericksState, A> VM._internal1(owner: LifecycleOwner?,prop1: KProperty1<S, A>,deliveryMode: DeliveryMode = RedeliverOnStart,action: suspend (A) -> Unit
) = stateFlow// 通过对象取出属性的值.map { MavericksTuple1(prop1.get(it)) }// 值发生变化了才会触发回调  .distinctUntilChanged().resolveSubscription(owner, deliveryMode.appendPropertiesToId(prop1)) { (a) ->action(a)}
  1. 主要是通过map将State转化为它的属性值

  1. 通过distinctUntilChanged方法开启防抖,相同的值不会回调,只有值修改了才会回调

  1. 需要注意的是因为使用了KProperty1,因此State的承载数据类必须避免混淆

如上,就是Mavericks的基本介绍,想了解更多的同学可参考:github.com/airbnb/mave…

LiveData实现属性监听

上面介绍了Mavericks是怎么实现局部刷新的,但直接使用它主要有两个问题

  1. 接入起来略微有点麻烦,例如Fragment必须实现MavericksView,有一定接入成本

  1. Mavericks的局部刷新是通过Flow实现的,但相信大多数人用的还是LiveData,有一定学习成本

下面我们就来看下LiveData怎么实现属性监听

//监听一个属性
fun <T, A> LiveData<T>.observeState(lifecycleOwner: LifecycleOwner,prop1: KProperty1<T, A>,action: (A) -> Unit
) {this.map {StateTuple1(prop1.get(it))}.distinctUntilChanged().observe(lifecycleOwner) { (a) ->action.invoke(a)}
}//监听两个属性
fun <T, A, B> LiveData<T>.observeState(lifecycleOwner: LifecycleOwner,prop1: KProperty1<T, A>,prop2: KProperty1<T, B>,action: (A, B) -> Unit
) {this.map {StateTuple2(prop1.get(it), prop2.get(it))}.distinctUntilChanged().observe(lifecycleOwner) { (a, b) ->action.invoke(a, b)}
}internal data class StateTuple1<A>(val a: A)
internal data class StateTuple2<A, B>(val a: A, val b: B)//更新State
fun <T> MutableLiveData<T>.setState(reducer: T.() -> T) {this.value = this.value?.reducer()
}
  1. 如上所示,主要是添加一个扩展方法,也是通过distinctUntilChanged来实现防抖

  1. 如果需要监听多个属性,例如两个属性有其中一个变化了就触发刷新,也支持传入两个属性

  1. 需要注意的是LiveData默认是不防抖的,这样改造后就是防抖的了,所以传入相同的值是不会回调的

  1. 同时需要注意下承载State的数据类需要防混淆

简单使用

上面介绍了LiveData如何实现属性监听,下面看下简单的使用

//页面状态,需要避免混淆
data class MainViewState(val fetchStatus: FetchStatus = FetchStatus.NotFetched,val newsList: List<NewsItem> = emptyList()
)//ViewModel
class MainViewModel : ViewModel() {private val _viewStates: MutableLiveData<MainViewState> = MutableLiveData(MainViewState())//只需要暴露一个LiveData,包括页面所有状态val viewStates = _viewStates.asLiveData()private fun fetchNews() {//更新页面状态_viewStates.setState {copy(fetchStatus = FetchStatus.Fetching)}viewModelScope.launch {when (val result = repository.getMockApiResponse()) {//...is PageState.Success -> {_viewStates.setState {copy(fetchStatus = FetchStatus.Fetched, newsList = result.data)}}}}}}//View层
class MainActivity : AppCompatActivity() {private fun initViewModel() {viewModel.viewStates.run {//监听newsListobserveState(this@MainActivity, MainViewState::newsList) {newsRvAdapter.submitList(it)}//监听网络状态observeState(this@MainActivity, MainViewState::fetchStatus) {//..}}}
}

如上所示,其实使用起来也很简单方便

  1. ViewModel只需对外暴露一个ViewState,避免了定义多个可变不可变LiveData的问题

  1. View层支持监听LiveData的一个属性或多个属性,支持局部刷新

总结

本文主要介绍了MVI架构下如何实现局部刷新,并重点介绍了Mavericks的基本使用与原理,并在其基础上使用LiveData实现了属性监听与局部刷新

通过以上方式,解决了MVI架构的性能问题,实现了MVI架构的更佳实践

如果你的ViewModel中定义了多个可变与不可变的LiveData,就算你不使用MVI架构,支持监听LiveData属性相信也可以帮助你精简一定的代码

如果本文对你有所帮助,欢迎点赞关注Star~

源码地址:

https://github.com/shenzhen2017/android-architecture

http://www.yayakq.cn/news/133124/

相关文章:

  • 移动端的网站青色系网站
  • 做网站需要空间跟域名吗校园网站首页模板
  • 建个人网站做导购怎么备案北京大学网站建设
  • 上海建设银行公司网站明星网页网站制作
  • 河南省安阳市建设银行网站公司网站模板凡建站
  • 网站整体框架seo兼职怎么收费
  • 局域网怎么做网站做网站用属于前端
  • 广东长城建设集团有限公司 网站工商网上注册营业执照
  • 钦州市住房和城乡建设局网站中国建行网银登录
  • 二手交易平台 网站开发苏州百度运营公司排名
  • ks3c ks4c做网站老薛主机卸载wordpress
  • 网站 被降权wordpress 替换图片
  • 湖北 网站 备案 时间宁波seo外包公司
  • 网站导航常用关键字网页设计与制作教程第五版答案
  • 网站速度测速模板网站多钱
  • 成都做公司网站福州网络公司有哪些
  • 湘乡网站建设上海app搭建
  • 佛山正规网站建设哪家好规划设计公司一般的毛利率是多
  • vs2017建设网站指定关键字 网站有更新就提醒
  • 做网站接单比分网站制作
  • 小众写作网站苗木企业网站建设源代码
  • 一个做特卖的网站wordpress导航菜单栏
  • wordpress 架站 电子书做手机版网站和做app差别
  • 网站建设尢金手指专业商丘微网站
  • 网站规划与网页设计第四版电子书网站制作怎么创业
  • 怎么样在百度搜到自己的网站网站网站制作需要多少钱
  • 郑州市做网站公司a汉狮网页制作与网站建设宝典 pdf
  • 做公众号的网站有哪些功能企业建设企业网站的好处有哪些
  • wordpress+仿站步骤十大最好玩网页游戏
  • 网站定制营销的过程做殡葬名片的网站