Android 使用DataBindingUtil 封装支持DataBinding的BaseActivityBaseFragment

Posted 匆忙拥挤repeat

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 使用DataBindingUtil 封装支持DataBinding的BaseActivityBaseFragment相关的知识,希望对你有一定的参考价值。

文章目录

历程

先是 使用了 viewBinding feature,以避免view id重名时,查找跳转布局错误。
后来,继续接触 dataBinding feature,期间还是使用之前定义的ViewBinding封装类,也没什么问题。
就是觉得每次,实例化还是要重复写一堆一样的代码,有点麻烦。一直想简化一下,刚好最近接触到了,记录一下


viewBinding 支持

开启 viewBinding 的支持

buildFeatures 
	viewBinding true

每个xml布局生成的 Binding类,都是实现了 ViewBinding 接口

为了简化实例化 ViewBinding 实例,有了如下封装

/**
 * desc   : ViewBinding、ViewDataBinding 的生成类的实例化 封装
 * author : stone
 * email  : aa86799@163.com
 * time   : 2022/5/14 22:44
 */
/**
 * AppCompatActivity#onCreate()使用
 */
inline fun <reified VB : ViewBinding> AppCompatActivity.inflate(): VB 
    return inflateBinding<VB>(layoutInflater).apply 
        setContentView(this.root)
    


/**
 * Dialog#onCreate() 使用
 */
inline fun <reified VB : ViewBinding> Dialog.inflate(): VB 
    return inflateBinding<VB>(layoutInflater).apply 
        setContentView(this.root)
    


/**
 * 继承自 ViewGroup 使用。
 * 例外情况:使用<merge>布局, 生成的ViewBinding 不会生成三个参数的 inflate方法, 所以调用本方法会报错。
 *   那就不能调用本封装方法,只能调用生成目标类的,如: XxxBinding.inflate(LayoutInflater.from(context), this)
 */
inline fun <reified VB : ViewBinding> ViewGroup.inflate(viewGroup: ViewGroup, attachToRoot: Boolean): VB 
    return inflateBinding(LayoutInflater.from(context), viewGroup, attachToRoot)


/**
 * Recycler.Adapter#onCreateViewHolder() 使用
 * 自定义ViewGroup中使用
 * ...
 * 以前需要 传递 parent:ViewGroup 对象来进行初始化的布局,都可以调用本方法
 */
inline fun <reified VB : ViewBinding> inflate(parent: ViewGroup): VB 
    return inflateBinding(LayoutInflater.from(parent.context), parent, false)


/**
 * 这是一个基础方法。所有创建ViewBinding对象的地方都可以直接调用。
 * 反射调用 ViewBinding.inflate(layoutInflater, viewGroup, attachToRoot) 。
 * 对于 Fragment、DialogFragment 都直接使用本方法。
 * 调用时,viewGroup可以不传,默认为null。
 */
@Suppress("UNCHECKED_CAST")
inline fun <reified VB : ViewBinding> inflateBinding(layoutInflater: LayoutInflater, viewGroup: ViewGroup? = null, attachToRoot: Boolean = false): VB 
    return VB::class.java.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java)
        .invoke(null, layoutInflater, viewGroup, attachToRoot) as VB


如上,泛型使用时,使用 reified 关键字,所以最终无法在 BaseActivity、BaseFragment 类定义中直接使用。如下,

class BaseExtendFragment<VB: ViewBinding> : Fragment() 
	protected lateinit var mBinding: VB
	override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? 
        mBinding = inflate(inflater, container) // 这里会报错,要求指定一个具体的ViewBinding类型
        return mBinding.root
    

所以改成了,子类来实例化

class BaseExtendFragment<VB: ViewBinding> : Fragment() 
	protected lateinit var mBinding: VB
	override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? 
        mBinding = (getViewBind(inflater, container, savedInstanceState) as ViewDataBinding)
        return mBinding.root
    
	abstract fun <VB : ViewBinding> getViewBind(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): VB

而子类实现,每次都要这么重复写一次:

override fun <VB : ViewDataBinding> getViewBind(inflater: LayoutInflater, container:ViewGroup?, savedInstanceState: Bundle?): VB 
    mBinding = inflateBinding(inflater, container)
    return mBinding as VB


Databinding 支持

开启 dataBinding 的支持

buildFeatures 
	dataBinding true

ViewDataBinding 其实这个类, 实现 ViewBinding 接口,本身是一个抽象类。
所以,只是前面的封装类中的 泛型类型改成 <reified VB : ViewDataBinding>,BaseActivity、BaseFragment 使用的地方相应的声明类型也是 ViewDataBinding
当然,子类实现时,还是有一段重复代码


使用 DataBindingUtil 封装简化

abstract class BaseBindActivity<VB : ViewDataBinding>(@LayoutRes resId: Int): BaseActivity() 

    protected val mBind: VB by lazy  DataBindingUtil.setContentView(this, resId) 


abstract class BaseBindFragment<VB : ViewDataBinding>(@LayoutRes private val resId: Int) : BaseFragment() 

    protected lateinit var mBind: VB

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? 
        mBind =  DataBindingUtil.inflate(inflater, resId, container, false)
        return mBind.root
    

直接使用 DataBinding 的gradle支持库中的工具类 DataBindingUtil来简化
对于Activity 使用 DataBindingUtil.setContentView(),其它的都可以使用 DataBindingUtil.inflate()

有些场景中,可能 UI-组件为null而报错了。如,混合webView时,在js回调中,再调用UI组件,这时宿主Activity可能已经finish了,而js回调开始执行
那就需要定义一个可空类型的 ViewDataBinding 实例

protected val _bind: VB? = mBind

以上是关于Android 使用DataBindingUtil 封装支持DataBinding的BaseActivityBaseFragment的主要内容,如果未能解决你的问题,请参考以下文章

Android 使用DataBindingUtil 封装支持DataBinding的BaseActivityBaseFragment

Android 数据绑定 DatabindingUtil 与绑定类

来自包含的 DataBindingUtil 绑定布局

`DataBindingUtil` 中的 `bind`、`inflate` 和 `setContentView` 有啥区别

Android初学第82天

Android的DataBinding原理