统一AppCompatActivity获取ViewModel、ViewBinding的入口-灵析社区

江江说技术


主要是统一下在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的创建,我们只需要拿到具体要创建ViewModelclass对象即可,那我们就可以将这个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的构造方法带有参数,请重写AppCompatActivitygetDefaultViewModelProviderFactory方法,实现ViewModelProvider.Factory接口自定义一个ViewModel的创建工厂并返回即可。

总结

经过上面的封装,我们就可以实现文章一开始使用的那种效果,使用起来也是很简单,除了传入的构造参数写起来稍微有一丢丢麻烦,看起来不美观哈!!


阅读量:1934

点赞量:0

收藏量:0