1.ViewModel可以通过下面两种方式创建:
通过(1)的方式会同步使用该ViewModel的所有页面,比如"关注"和"推荐"都使用下面(1)的方式,则会出现在关注页刷新数据,同时推荐页的数据也刷新了的问题,这种方式适用于两个一模一样的页面。如果不需要同时刷新该ViewModel的所有页面,请采用下面(2)的方式,即New的方式,New的方式只会在自己使用的地方调用才会刷新。两种方式如下:
(1)Mvrx自己的注入方式
//在fragment中使用时通过mvrx自己的注入方式使用需要实现这个
companion object : MvRxViewModelFactory<DynListViewModel, DynamicListState> {
override fun create(
viewModelContext: ViewModelContext,
state: DynamicListState
): DynListViewModel {
val repo by viewModelContext.app<App>().kodein.instance<FollowRepo>()
return FollowViewModel(state, repo)
return DynListViewModel(state)
}
(2)New的方式
//采用new的方式
private val viewModel: DynDetailViewModel by lazy {
DynDetailViewModel()
}
2.MvRxView的postInvalidate()调用问题
(1)默认在初始化的时候会采用ViewModel监听的方式调用,所以在数据改变后会自动刷新页面
viewModel.subscribe { postInvalidate() }
(2)在页面中监听数据回调
override fun invalidate() {
com.airbnb.mvrx.withState(viewModel) { state ->
runOnUiThread {
......
}
}
}
(3)在Epoxy中监听,分2部
//1.刷新Controller
override fun invalidate() {
epoxyController.requestModelBuild()
}
//2.在Controller中获取数据
private val epoxyController = MvRxEpoxyController {
com.airbnb.mvrx.withState(viewModel) { state ->
}
}
3.Epoxy数据变化刷新问题
(1)当数据变化后,如果会调用到ViewModel中的copy方法,则不需要在变化的地方调用postInvalidate()方法,内部会通过数据监听方式触发subscribe的invalidate去刷新Controller
//1. Controller的item代码
dynCommentHeaderItem {
id("comment_header_top")
totalSize(state.totalSize)
sortByHot(state.sortByHot)
onClickSort {
viewModel.changeSortByHot(dynDetailSticky.visibility == View.VISIBLE)//调用排序的代码
}
}
//2.ViewModel中的刷新代码
fun changeSortByHot(needScrollTop: Boolean) {
withState { state ->
setState {
copy(
dynamicBean = state.dynamicBean,
totalSize = state.totalSize,
sortByHot = !state.sortByHot,
needScrollTop = needScrollTop,
commentList = sortData(state.commentList, !state.sortByHot)
)
}
}
}
(2)不采用数据监听,直接修改数据后刷新
//Controller的item代码
dynCommentItem {
id("comment_" + it.id)
dynId(dynId)
commentBean(it)
onClickReply { syncOpenKeyboard(true, it) }
onClickPraise { bean ->
val newBean = bean.copy(isPraise = !bean.isPraise)
if (!newBean.isPraise) {
newBean.praiseNum += -1
mContext.toast("取消点赞")
} else {
newBean.praiseNum += 1
mContext.toast("点赞")
}
Collections.replaceAll(state.commentList, bean, newBean)//1.更换数据
postInvalidate()//2.直接调用刷新
}
onItemClick { showCopyDialog(it) }
}
(3)更换数据的两种方式,由于Epoxy更换数据后可能出现不刷新的问题(因为id一致),所以需要采用copy的方式刷新
//1.Collections.replaceAll
Collections.replaceAll(beanList, oldBean, oldBean.copy())
//2.直接采用新的数据替换旧数据
beanList.set(beanList.indexOf(oldBean),oldBean.copy())
4.一个简单的viewmodel.kt代码
data class SettingState(
val cacheSize: Long = 0,
val request: Async<Boolean> = Uninitialized
) : MvRxState
class SettingViewModel(
state: SettingState = SettingState()
) : MvRxViewModel<SettingState>(state) {
......
}
5.页面中引用
class SettingActivity : CommTitleActivity(), MvRxView {
private val viewModel: SettingViewModel by lazy {
SettingViewModel()
}
override fun initData() {
viewModel.subscribe { postInvalidate() }
}
override fun invalidate() {
com.airbnb.mvrx.withState(viewModel) { state ->
runOnUiThread {
......
}
}
}
}
网友评论