MVVMCapybara 一个Android 架构
一个基于Android MVVM的架构????
以下文章,我会把本架构称为 Capybara
放下Github链接先https://github.com/Ubitar/MVVMCapybara
Capybara 使用databinding + fragmentation
搭建,仅包含Activity
及Fragment
等基础组件等功能,
可能有些人喜欢用 navigation
,架构有分层,大家可以自己fork下来删减定制。
前言
在阅读 Capybara 前,我会默认大家都看过databinding、fragmentation、LiveData
的使用方法,及kotlin的使用,kt真香。
不过我希望先阅读一下下面链接里的大佬文章,加深对MVVM和数据驱动的了解。
https://www.zhihu.com/question/30976423/answer/106134677
https://www.jianshu.com/p/1fcda521fcda 禁止在layout中写复杂逻辑
当然,如果你做过Vue或者微信小程序那更好理解了,即时那时你会嫌弃安卓的MVVM,或者充满黑人问号
结构简述
Capybara 主要通过让组件继承IView 、IViewModel 、IModel
这3个接口来实现的。
View 层可以为你的Activity、Fragment或者DialogFragment
Model 层为为你的业务提供网络请求服务或者数据库读存服务
ViewModel 中间层 则是负责处理你的业务逻辑,从Model中获取数据进行处理,并对View进行更新的
图中BaseMvvMActivity
(我写错成了BseMvvMActivtivty了)、BaseViewModel
和BaseModel
为MVVM的实现抽象类,在不同的生命周期中实现并调用了MVVM接口。
而BaseMvvMFragment
也类似有同样的实现,只不过因其生命周期,调用方法的位置有些不同,具体内容需要大家去浏览源码。
如果你想支持例如Popup
之类的组件,也可以了解架构的大体走向后通过实现上方所提及的3个接口进行实现,当然,前提是你的这类popup
组件得有一个说得过去的生命周期。
食用方法
1、新建一个布局文件,里面就只有一个按钮
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModelName"
type="com.example.example.demo1.Demo1ViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:orientation="vertical">
<Button
android:id="@+id/btn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text='@{"点击这个按钮 "+viewModelName.count}'
android:textAllCaps="false"
app:onClick="@{viewModelName.onClickBtn1}"
tools:text="点击这个按钮" />
</LinearLayout>
</layout>
2、新建一个ViewModel
,继承自BaseActivityViewModel
**注意:**这个ViewModel是继承自ActivityViewModel的,因为我们接下来要创建的是其相应的Activity
,如果你要创建的是Fragment
,那么你需要继承的则是BaseFragmentViewModel
,同理,Dialog
是BaseDialogViewModel
class Demo1ViewModel(application: Application) : BaseActivityViewModel<BaseModel>(application) {
val count = MutableLiveData<Int>(0)
/** 这个是 MVVM 中的 Model层,如没有网络或数据库需求,传NUll即可 */
override fun getModel(): Class<BaseModel>? = null
//用于初始化RecyclerView adapter的事件监听
override fun initEvent() {
super.initEvent()
}
//初始化数据或者获取数据
override fun initData() {
super.initData()
}
fun onClickBtn1(view: View) {
count.value = count.value!! + 1
}
}
3、新建你的Activity
,继承 BaseActivity
并实现getLayoutId()
和getViewModelId()
提供布局Id和ViewModel在布局中的变量名称
class Demo1Activity: BaseActivity<ActivityDemo1Binding, Demo1ViewModel>() {
/** 你的布局Id **/
override fun getLayoutId(inflater: LayoutInflater, savedInstanceState: Bundle?): Int = R.layout.activity_demo1
/** 布局中ViewModel的Name */
override fun getViewModelId(): Int =BR.viewModelName
/**
* 下方函数运行顺序(从上往下顺序运行)
*
* initParams()
* initViewModelParams()
* initView()
* onBindObservable()
* ViewModel.initEvent()
* ViewModel.initData()
*
*/
//用于接收并处理从上一个界面传递过来的数据
override fun initParams() {
super.initParams()
}
//如果有需要,可以通过这个函数把初始数据传到ViewModel
override fun initViewModelParams() {
super.initViewModelParams()
viewModel.count.value = 100
}
// 初始化RecyclerView或者其他View
override fun initView() {
super.initView()
}
// 注册ViewModel中变量值的改变,可用于ViewModel向View传递信息或操作
override fun onBindObservable() {
super.onBindObservable()
}
}
4、或许你的项目里会有读取数据库或者网络的时候,那么你就需要实现相应的Model层,编写一个Model层文件
class Demo3Model(
private val viewModel: Demo3ViewModel
) : BaseModel(viewModel) {
fun toLogin(account: String, password: String) {
//模拟登录
Flowable.timer(1000, TimeUnit.MILLISECONDS)
.doOnSubscribe { ToastUtils.showShort("加载中") }
//这个是AutoDispose 如果要Rxlifecycle你要去想办法自己更换
// .`as`(AutoDisposeUtil.fromOnDestroy(viewModel.lifecycle.get()!!))
.subscribe({
viewModel.afterLoginSuccess()
}, {
println(it)
}).isDisposed
}
override fun onCleared() {
super.onCleared()
}
}
在ViewModel处编写getModel()
函数的返回值,同时别忘了修改类上方的泛型
class Demo3ViewModel(application: Application) : BaseActivityViewModel<Demo3Model>(application) {
//改这里,还有上方的泛型
override fun getModel(): Class<Demo3Model>? = Demo3Model::class.java
var account = MutableLiveData<String>("")
var password = MutableLiveData<String>("")
fun onClickLogin(view: View) {
// model是从父类继承的Model层的引用
model.toLogin(account.value ?: "", password.value ?: "")
}
fun afterLoginSuccess() {
ToastUtils.showShort("登陆成功")
}
}
关于fragmentation
在这个架构上的应用可以查看源码demo4
常见问题
1、这架构胶水代码好多
额。。。。这个我也想解决,但是奈何我还不会写插件一键生成
2、MVVM好用不
这个问题就很刁钻了,MVVM和MVP一个自底向上,一个自顶向下,写法完全相反,而且MVVM并不是android原生就有的,稍微复杂点的逻辑不能写在xml(或者说太多if条件),xml报错的时候也一脸懵逼,只能一个一个注释排查,你想从不是MVVM架构的项目中复制代码?对不起,大部分你都要重写。
但是好处还是有的,感触最深的还是改了只改变一个变量就显示隐藏了多个View,其次是@BindingAdapter
对UI操作的封装,其他的还要自己去体会。
上一篇: 揭秘:朱元璋究竟有没有火烧庆功楼?
推荐阅读
-
android组件化架构(速览android组件和使用技巧)
-
Android登录代码MVP架构详解
-
用Python编写一个简单的CS架构后门的方法
-
android的activity跳转到另一个activity
-
Android开发笔记之:如何安全中止一个自定义线程Thread的方法
-
使用React服务端渲染Next.js框架构建一个简单项目(实例)
-
Android 中启动自己另一个程序的activity如何实现
-
Android 启动另一个App/apk中的Activity实现代码
-
浅谈Android获取ImageView上的图片,和一个有可能遇到的问题
-
Android中一个应用实现多个图标的几种方式