一看就会 Android框架DataBinding的使用与封装

语言: CN / TW / HK

theme: juejin highlight: a11y-dark


本文已参与「新人创作礼」活动,一起开启掘金创作之路。

Android中DataBinding的封装

先简单的介绍DataBinding

DataBinding 是谷歌官方发布的一个框架,是 MVVM 模式在 Android 上的一种实现,减少了布局和逻辑的耦合,数据能够单向或双向绑定到 layout 文件中,有助于防止内存泄漏,而且能自动进行空检测以避免空指针异常。

虽然现在Xml中可以写逻辑代码了,但是还是推荐不要直接在xml里面写复杂的逻辑,如果有必要的需求,我们可以用BindingAdapter 自定义属性。

话不多说,快来看看怎么用!

一. 如何使用

1.1.数据的绑定

gradle开启功能, 4.0以上和以下的有区别。现在很少有4.0以下的吧。 ```js android { viewBinding { enabled = true } dataBinding{ enabled = true } }

// Android Studio 4.0 android { buildFeatures { dataBinding = true viewBinding = true } } 开启DataBinding之后,xml会默认编译为Java对象,如果不想自己的非DB的xml被编译,可以在xml添加忽略js tools:viewBindingIgnore="true" ```
正常的xml中需要用layout布局包裹,模板如下:

```xml

<data>

    <variable
        name="testBean"
        type="com.guadou.kt_demo.demo.demo12_databinding_texing.TestBindingBean" />

    <variable
        name="click"
        type="com.guadou.kt_demo.demo.demo12_databinding_texing.Demo12Activity.ClickProxy" />

</data>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:orientation="vertical">

     <!--    注意双向绑定的写法    -->
       <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@={click.etLiveData}" />

       <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="绑定(获取值)"
            binding:clicks="@{click.showETText}" />

     <include
        layout="@layout/include_databinding_test"
        binding:click="@{click}"
        binding:testBean="@{testBean}" />

     <com.guadou.kt_demo.demo.demo12_databinding_texing.CustomTestView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        binding:clickProxy="@{click}"
        binding:testBean="@{testBean}" />

</LinearLayout>

```


xml中data闭包是数据源,我们定义了类型之后需要在Activity/Fragment中设置,例如:

kotlin val view = CommUtils.inflate(R.layou.include_databinding_test) //绑定DataBinding 并赋值自定义的数据 DataBindingUtil.bind<IncludeDatabindingTestBinding>(view)?.apply { testBean = TestBindingBean("haha", "heihei", "huhu") click = clickProxy }

绑定数据的类型我们可以用LiveData或Flow都可以: kotlin val etLiveData: MutableLiveData<String> = MutableLiveData() val etFlow: MutableStateFlow<String?> = MutableStateFlow(null) 直接XML中双向绑定数据或者单向的绑定数据即可 ```xml

```

1.2 布局的绑定

inflate/include/ViewStub/CustomView如何绑定布局与DataBinding

include/ViewStub这样用: xml <include layout="@layout/include_databinding_test" binding:click="@{click}" binding:testBean="@{testBean}" /> include_databinding_test: ```xml

<data>

    <variable
        name="testBean"
        type="com.guadou.kt_demo.demo.demo12_databinding_texing.TestBindingBean" />

    <variable
        name="click"
        type="com.guadou.kt_demo.demo.demo12_databinding_texing.Demo12Activity.ClickProxy" />

    <import
        alias="textUtlis"
        type="android.text.TextUtils" />
</data>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:layout_marginTop="15dp"
        android:text="下面是赋值的数据"
        binding:clicks="@{click.testToast}"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{testBean.text1}" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{testBean.text2}" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{testBean.text3}" />

</LinearLayout>

include:kotlin //Activity中动态的加载布局 fun inflateXml() { //给静态的xml,赋值数据,赋值完成之后 include的布局也可以自动显示 mBinding.testBean = TestBindingBean("haha", "heihei", "huhu")

        //获取View
        val view = CommUtils.inflate(R.layout.include_databinding_test)
        //绑定DataBinding 并赋值自定义的数据
        DataBindingUtil.bind<IncludeDatabindingTestBinding>(view)?.apply {
            testBean = TestBindingBean("haha1", "heihei1", "huhu1")
            click = clickProxy
        }
        //添加布局
        mBinding.flContent.apply {
            removeAllViews()
            addView(view)
        }
    }

自定义View,在Xml中定义和在Activity中手动定义是一样的。这里演示手动定义赋值:kotlin fun customView() { //给静态的xml,赋值数据,赋值完成之后 include的布局也可以自动显示 mBinding.testBean = TestBindingBean("haha2", "heihei2", "huhu2")

        //动态的添加自定义View
        val customTestView = CustomTestView(mActivity)
        customTestView.setClickProxy(clickProxy)
        customTestView.setTestBean(TestBindingBean("haha3", "heihei3", "huhu3"))

        mBinding.flContent2.apply {
            removeAllViews()
            addView(customTestView)
        }
    }

``` 自定义Viewr中绑定属性:

```xml class CustomTestView @JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : LinearLayout(context, attrs, defStyleAttr) {

init {
    orientation = VERTICAL

    //传统的方式添加
    val view = CommUtils.inflate(R.layout.layout_custom_databinding_test)
    addView(view)

}

//设置属性
fun setTestBean(bean: TestBindingBean?) {

    bean?.let {
        findViewById<TextView>(R.id.tv_custom_test1).text = it.text1
        findViewById<TextView>(R.id.tv_custom_test2).text = it.text2
        findViewById<TextView>(R.id.tv_custom_test3).text = it.text3
    }

}

fun setClickProxy(click: Demo12Activity.ClickProxy?) {
    findViewById<TextView>(R.id.tv_custom_test1).click {
        click?.testToast()
    }
}

} ```

1.3 事件的绑定

比较常见的是Click和控件的事件监听回调:

xml <EditText android:id="@+id/et_redpack_money" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_9dp" android:layout_weight="1" android:background="@null" android:hint="0.00" android:inputType="numberDecimal" android:paddingLeft="@dimen/d_9dp" android:singleLine="true" android:textColor="@color/black_33" android:textCursorDrawable="@null" android:textSize="@dimen/d_25sp" binding:typefaceSemiBold="@{true}" binding:onTextChanged="@{click.onAmountChanged}" binding:setDecimalPoints="@{2}" /> Click封装的代码中使用高阶函数来接收回调 ```kotlin inner class ClickProxy {

    //金额变化
    val onAmountChanged: (String) -> Unit = {
        calculationTotalAmount(it)
    }
   ...
}

**点击事件的封装:** 注意一个是我的封装clicks,一个是远程android的属性clickxml

「其他文章」