主要是统一下在AppCompatActivity获取ViewModel+ViewBinding的入口,先看下最终的封装效果:
下面就让我们一步步的实现下这种效果:
BaseMvvmActivity
abstract class BaseMvvmActivity() : AppCompatActivity() {}
这个类继承了AppCompatActivity
,将作为之后界面继承的的基类,在这个类中统一获取ViewModel
+ViewBinding
的入口。
ViewBinding
的获取入口ViewBinding
的具体创建函数是ViewBinding.inflate()
,首先我们要明确一个点,函数和函数类型是可以相互转化的:
private val vb: (LayoutInflater) -> ActivityMainBinding = ActivityMainBinding::inflate
我们将这个创建函数转换成一个函数类型并作为构造参数传入BaseMvvmActivity
,其次还要在BaseMvvmActivity
中传入<T: ViewBinding>
,这样才能够获取ViewBinding的具体实现类型:
abstract class BaseMvvmActivity<T: ViewBinding>(
private val vb: (LayoutInflater) -> ActivityMainBinding
): AppCompatActivity() {
protected lateinit var mBinding: VB
}
然后重写onCreate()
方法,在该方法中完成具体ViewBinding的创建
以及当前界面根布局的设置
:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = vb(layoutInflater)
setContentView(mBinding.root)
}
这样我们就可以在界面内中这样使用:
class ZygoteActivity : BaseMvvmActivity<ActivityMainBinding>(
ActivityMainBinding::inflate
) {
fun test2() {
//直接从父类中获取ViewBinding的实现对象
mBinding.iconIv.visibility = View.VISIBLE
}
}
请注意,Fragment
可不能进行如此封装,因为如果把ViewBinding
的创建函数作为构造函数的一个参数传入,但Fragment
创建销毁被重建后,该参数就直接丢失了,这就会造成后续在onCreateView()
方法中调用该参数创建ViewBinding
时直接空指针异常了。
ViewModel
的获取入口对于ViewModel的创建,我们只需要拿到具体要创建ViewModel
的class
对象即可,那我们就可以将这个class
对象直接通过构造参数传入到BaseMvvmActivity
中即可:
abstract class BaseMvvmActivity<VB : ViewBinding, VM : ViewModel>(
private val vb: (LayoutInflater) -> VB, private val vmClass: Class<VM>
) : AppCompatActivity() {
}
在BaseMvvmActivity
中通过懒加载
的形式完成具体ViewModel
的创建:
protected val mViewModel: VM by lazy {
ViewModelProvider(viewModelStore, defaultViewModelProviderFactory).get(vmClass)
}
然后就可以这样使用:
class ZygoteActivity : BaseMvvmActivity<ActivityMainBinding, MainViewModel>(
ActivityMainBinding::inflate,
MainViewModel::class.java
) {
fun test2() {
mBinding.iconIv.visibility = View.VISIBLE
//使用ViewModel
mViewModel.data1.observe(this) {
}
}
}
请注意,如果要创建的具体ViewModel
的构造方法带有参数,请重写AppCompatActivity
的getDefaultViewModelProviderFactory
方法,实现ViewModelProvider.Factory
接口自定义一个ViewModel
的创建工厂并返回即可。
经过上面的封装,我们就可以实现文章一开始使用的那种效果,使用起来也是很简单,除了传入的构造参数写起来稍微有一丢丢麻烦,看起来不美观哈!!
阅读量:1934
点赞量:0
收藏量:0