前言
android 的架构模式从早期的MVC,到分离activity职责的MVP,到数据双向绑定的MVVM,到最近开始了解到新的架构模式mvi。虽然MVVM已经很成熟,但是有新的东西总归要了解下。然而MVI比较典型的代表自然是Airbnb的 Mavericks了,今天就写个hello world拉。当然我会配合他的好搭档Epoxy来使用,下面开始进入正题。
代码部分
引入相关仓库
api 'com.airbnb.android:mavericks:3.0.6'
api 'com.airbnb.android:epoxy:5.0.0'
kapt 'com.airbnb.android:epoxy-processor:5.0.0'
然后我们就可以开始快乐的编码了,接口数据使用hong yang鸿洋的 玩Android Api拉。
首先需要构建三个关键的类 MavericksState MavericksViewModel MavericksView,这样就可以按照MVI的模式开些代码了。
//状态类
data class SystemState(
val systemBean: Async<WanApiResponse<List<SystemBean>>> = Uninitialized,
) : MavericksState
//view model 这里引入了仓库
class SystemViewModel(state: SystemState, private val repository: HomeRepository) :
MvRxViewModel<SystemState>(state) {
init {
getSystemDataList()
}
private fun getSystemDataList() {
repository.getSystemDataList().execute {
copy(systemBean = it)
}
}
companion object : MavericksViewModelFactory<SystemViewModel, SystemState> {
override fun create(
viewModelContext: ViewModelContext,
state: SystemState
): SystemViewModel {
val api: HomeRepository by viewModelContext.activity.inject()
return SystemViewModel(state, api)
}
}
}
//仓库中的代码
fun getSystemDataList() = flow {
emit(apiService.getSystemDataList())
}.flowOn(Dispatchers.IO)
以上就是数据部分,下面是数据关联fragment了,推荐是单activity多fragment的开发模式。
首先xml中要使用epoxy中的recyclerview
<com.airbnb.epoxy.EpoxyRecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
然后是fragment中的使用,使用前我们需要讲列表的item通过epoxy的注解处理器生成对应的ModelView,通过绑定xml进行属性赋值。结果就是我们不需要写adapter了。是不是很惊喜!!用了就回不去的感觉。
这里是item的代码,如下:
@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class ItemSystem @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
private val binding: ArticleSystemItemBinding by viewBinding()
init {
orientation = VERTICAL
}
@TextProp
fun setTitle(title: CharSequence?) {
binding.tvChapterName.text = title
}
@TextProp
fun setDes(des: CharSequence?) {
binding.tvDesc.text = des
}
@CallbackProp
fun setClickListener(clickListener: OnClickListener?) {
setOnClickListener(clickListener)
}
}
两个文字赋值和一个点击事件,接这么简单,下边开始关联recycler view拉,我们看fragment中的代码。
生成一下viewmodel吧
val viewModel: SystemViewModel by fragmentViewModel()
监听一下state的数据变化拉
//构建Models
binding.recyclerView.buildModelsWith(object : EpoxyRecyclerView.ModelBuilderCallback {
override fun buildModels(controller: EpoxyController) {
controller.buildModels()
}
})
//监听数据并填充
private fun EpoxyController.buildModels() = withState(viewModel) { state ->
state.systemBean.invoke()?.data?.forEach { system ->
var stringName = ""
system.children.forEach {
stringName += it.name + ","
}
itemSystem {
id(system.id)
title(system.name)
des(stringName)
}
}
}
//请求构建
override fun invalidate() {
binding.recyclerView.requestModelBuild()
}
以上基本完成数据了,就这么简单拉,完成如上步骤hello world 就完成了。
结束
代码我写到我的GitHub上了,yihu5566/wanadnroid ,分支选择mvi-test即可查看源码。
只分享用法不存在原理分析,感谢观看,谢谢。