Android 使用DataBindingUtil 封装支持DataBinding的BaseActivity、BaseFragment

历程

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


viewBinding 支持

开启 viewBinding 的支持

buildFeatures {
	viewBinding true
}

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

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

/**
 * desc   : ViewBinding、ViewDataBinding 的生成类的实例化 封装
 * author : stone
 * email  : [email protected]
 * 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
当然,子类实现时,还是有一段重复代码

扫描二维码关注公众号,回复: 15193845 查看本文章

使用 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

猜你喜欢

转载自blog.csdn.net/jjwwmlp456/article/details/128275953