Jetpack DataBinding

Jetpck 才是真的豪華全家桶

引言

  • DataBinding 實現(xiàn)了視圖與數(shù)據(jù)的雙向綁定,代碼簡潔,Activity 中代碼不再因此膨脹。
  • DataBinding 帶來了軟件架構(gòu)的新模式 MVVM 。
  • 如果使用 DataBinding 的主要目的是取代 findViewById() 調(diào)用,請考慮改用 ViewDataBinding。
  • 靈活強大的框架,會帶來學習成本的提升,深度掌握它,做工具的主人。

整體預(yù)覽

Jetpack DataBinding 概覽圖

用圖說話

?文章較長,考慮到心急的寶寶們看不到最后,所以總結(jié)性的圖,放到最前面吧!

1. DataBinding 數(shù)據(jù)流向 生成綁定類

Jetpack DataBinding 數(shù)據(jù)流向 生成綁定類

2. DataBinding 數(shù)據(jù)流向 綁定類相互關(guān)系

Jetpack DataBinding 數(shù)據(jù)流向 綁定類相互關(guān)系

3. DataBinding 數(shù)據(jù)流向 普通-數(shù)據(jù)對象

Jetpack DataBinding 數(shù)據(jù)流向 普通-數(shù)據(jù)對象

4. DataBinding 數(shù)據(jù)流向 可觀察-數(shù)據(jù)對象

Jetpack DataBinding 數(shù)據(jù)流向 可觀察-數(shù)據(jù)對象

5. DataBinding 數(shù)據(jù)流向 雙向數(shù)據(jù)綁定

Jetpack DataBinding 數(shù)據(jù)流向 雙向數(shù)據(jù)綁定

6. DataBinding 數(shù)據(jù)流向 橫向?qū)Ρ?/strong>:

Jetpack DataBinding 數(shù)據(jù)流向 橫向?qū)Ρ?/div>

1. 語法說明

1.1 環(huán)境配置

? 模塊啟用

//build.gradle
android {
        buildFeatures {
            dataBinding true
        }
    }

1.2 布局文件格式

1.2.1 數(shù)據(jù)綁定布局文件

?以根標記 layout 開頭,后跟 data 元素和 view 根元素。綁定視圖的根其實是View根元素。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        //data 中的 user 變量描述了可在此布局中使用的屬性。
        <variable
            name="user"
            type="com.kejiyuanren.jetpack.databinding.ViewModel" />
    </data>

    //布局中的表達式使用“@{}”語法寫入特性屬性中。
    //在這里,TextView文本被設(shè)置為 user 變量的 userName 屬性
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".databinding.DataBindingActivity">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"
            android:text="@{user.userName}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Tips:布局表達式應(yīng)保持精簡,因為它們無法進行單元測試,并且擁有的 IDE 支持也有限。

1.2.2 數(shù)據(jù)對象

?定義一個最簡單的數(shù)據(jù)對象。

data class ViewModel(val userName:String)

1.3 生成綁定類

?生成的綁定類將布局變量與布局中的視圖關(guān)聯(lián)起來。所有生成的綁定類都是從 ViewDataBinding 類繼承而來的。系統(tǒng)會為每個布局文件生成一個綁定類(綁定類名稱規(guī)則:布局文件名為 activity_main.xml,因此生成的對應(yīng)類為 ActivityMainBinding)。

1.3.1 創(chuàng)建綁定對象

?創(chuàng)建綁定類的方式有很多種。

class DataBindingActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //普通實現(xiàn)
//        setContentView(R.layout.activity_data_binding2)

        //綁定實現(xiàn) 1
        val binding: ActivityDataBinding2Binding = DataBindingUtil.setContentView(
            this,
            R.layout.activity_data_binding2
        )
        binding.user = ViewModel("kejiyuanren - 1")

        //綁定實現(xiàn)2(其實binding類的生成,主要就是 DataBindingUtil類 和 xxxBinding類 中的實現(xiàn))
//        val binding2: ActivityDataBinding2Binding =
//            ActivityDataBinding2Binding.inflate(layoutInflater)
//        setContentView(binding2.root)
//        binding2.user = ViewModel("keyijiyuanren-2")
    }
}

Tips:綁定類創(chuàng)建匯總(xxxBinding最終依然會調(diào)到 DataBindingUtil)。

創(chuàng)建綁定對象匯總

1.3.2 帶 ID 的視圖

?數(shù)據(jù)綁定庫會針對布局中具有 ID 的每個視圖在綁定類中創(chuàng)建不可變字段。相較于針對布局中的每個視圖調(diào)用 findViewById() 方法,這種機制速度更快。如果沒有數(shù)據(jù)綁定,則 ID 并不是必不可少的,但仍有一些情況必須能夠從代碼訪問視圖。

1.3.3 變量

?數(shù)據(jù)綁定庫為布局中聲明的每個變量生成訪問器方法( setter 和 getter )。

//xml code
<layout ……>

    <data>

        <variable
            name="star"
            type="int" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        ……>
        <TextView
            ……
            android:text="@{String.valueOf(star)}" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

//java code
binding.setStar(5)
1.3.4 ViewStub

?ViewStub是可用于延遲加載視圖的組件。在DataBinding中的用法如下:

//xml code -> activity.xml
<layout ……>

    <androidx.constraintlayout.widget.ConstraintLayout
        ……>
        <ViewStub
            android:layout="@layout/view_stub_tip"
            …… />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

//xml code -> view_stub_tip.xml
<layout ……>

    <data>
        <variable
            name="tipModel"
            type="com.kejiyuanren.jetpack.databinding.TipViewModel" />
    </data>

    <TextView
        android:text="@{tipModel.tipInfo}"
        ……/>
</layout>

//java code
fun viewStubAdd() {
    //視圖擴展監(jiān)聽器, 獲取已經(jīng)生成的綁定類,并執(zhí)行更新操作
    binding.viewStubExpand.setOnInflateListener { _, inflated ->

        //OK : 方式 1,直接獲取了view的binding緩存(因為binding已經(jīng)生成過了,在ViewStubProxy中)
        val vb1: ViewStubTipBinding? = DataBindingUtil.bind(inflated)

        //OK : 方式 2,直接獲取 ViewStubProxy中的 binding緩存
//            val vb2 = binding.viewStubExpand.binding as ViewStubTipBinding

        //ERROR : 方式 3, 直接通過擴展layout的綁定類生成,因為在ViewStubProxy中已經(jīng)創(chuàng)建過了
        //創(chuàng)建過的binding類會清空view對應(yīng)的tag, 所以會報錯(view must have a tag)
        //這種機制也保證了,binding類的單例特性
//            val vb3 = ViewStubTipBinding.bind(inflated)

        vb1?.tipModel = TipViewModel("666")
    }

    //延遲5s觸發(fā)加載擴展視圖
    binding.root.postDelayed({
        val vs: ViewStub? = binding.viewStubExpand.viewStub
        vs?.inflate()
    }, 5000)
}
1.3.5 動態(tài)變量

?有時,系統(tǒng)并不知道特定的綁定類。例如,針對任意布局運行的 RecyclerView.Adapter 不知道特定綁定類。在調(diào)用 onBindViewHolder() 方法時,仍必須指定綁定值。比如:RecyclerView 綁定到的所有布局都有 itemModel 變量。

//xml code
<layout ……>
    <data>
        <variable
            name="itemModel"
            type="com.kejiyuanren.jetpack.databinding.ItemViewModel" />
    </data>

    <TextView
        android:text="@{itemModel.name}"
        …… />
</layout>

//java code
import com.kejiyuanren.jetpack.BR   //記得要引入 BR,不然會報錯(Unresolved reference: BR)
class RvAdapter(private val mData: List<ItemViewModel>) :
    RecyclerView.Adapter<RvAdapter.RvViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RvViewHolder {
        val db = ItemDbRvTextBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return RvViewHolder(db)
    }

    override fun getItemCount(): Int {
        return mData.size
    }

    override fun onBindViewHolder(holder: RvViewHolder, position: Int) {
        holder.vb.setVariable(BR.itemModel, mData[position])
        //當可變或可觀察對象發(fā)生更改時,綁定會按照計劃在下一幀之前發(fā)生更改。
        //但有時必須立即執(zhí)行綁定。要強制執(zhí)行,請使用 executePendingBindings()` 方法。
        holder.vb.executePendingBindings() 
    }

    class RvViewHolder(binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {
        val vb = binding
    }
}
1.3.6 自定義綁定類名稱

?默認情況下,綁定類是根據(jù)布局文件的名稱生成的。通過調(diào)整 data 元素的 class 特性,綁定類可重命名或放置在不同的包中。

//xml code
<layout ……>
    <data class="KeJiYuanRen">
    </data>
</layout>

//java code
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //綁定類已經(jīng)變?yōu)榱俗远x,不再是默認的命名規(guī)則類
        val binding: KeJiYuanRen = DataBindingUtil.setContentView(
            this,
            R.layout.activity_data_binding2
        )
    }

1.4 綁定適配器

?綁定適配器負責發(fā)出相應(yīng)的框架調(diào)用來設(shè)置值。

1.4.1 自動選擇方法

?您可以使用數(shù)據(jù)綁定為任何 setter 創(chuàng)建特性。以 android:text="@{user.name}" 表達式為例,庫會查找接受 user.getName() 所返回類型的 setText(arg) 方法。如果 user.getName() 的返回類型為 String,則庫會查找接受 String 參數(shù)的 setText() 方法。

1.4.2 指定自定義方法名稱

?一些屬性具有名稱不符的 setter 方法(比如TextView中就沒有setText(arg : Int))。那么就可以自定義方法名稱,使用 BindingMethods注釋與 setter 相關(guān)聯(lián)。注釋與類一起使用,可以包含多個 BindingMethod注釋,每個注釋對應(yīng)一個重命名的方法。

//xml code
<layout ……>
    <data>
        <variable
            name="star"
            type="int" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        ……>
        <com.kejiyuanren.jetpack.databinding.Number
            app:number="@{star}"
            ……/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

//java code
@BindingMethods(    //自定義方法名稱集合,可以包含多個BindingMethod
    value = [       //這是個數(shù)組
        BindingMethod(
            type = TextView::class,  //要操作的屬性屬于哪個類
            attribute = "number",    //xml屬性,使用(app:number=“20”)
            method = "setTextNumber" //指定xml屬性對應(yīng)的set方法,參數(shù)類型要對應(yīng)
        )]
)

class Number @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : TextView(context, attrs, defStyleAttr) {

    fun setTextNumber(number : Int) {
        text = number.toString()
    }
}
1.4.3 提供自定義邏輯

?一些屬性需要自定義綁定邏輯。參數(shù)類型非常重要。第一個參數(shù)用于確定與特性關(guān)聯(lián)的視圖類型,第二個參數(shù)用于確定在給定特性的綁定表達式中接受的類型。

//xml code
<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" />

//java code
  //如果不需要同時滿足,則requireAll設(shè)置為false
@BindingAdapter(value = ["imageUrl", "placeholder"], requireAll = true) 
    fun loadImage(view: ImageView, url: String, error: Drawable) {
        Picasso.get().load(url).error(error).into(view)
    }
1.4.4 自動轉(zhuǎn)換對象

?當綁定表達式返回 Object 時,庫會選擇用于設(shè)置屬性值的方法。如果參數(shù)類型不明確,則必須在表達式中強制轉(zhuǎn)換返回類型。

1.4.5 自定義轉(zhuǎn)換

?在某些情況下,需要在特定類型之間進行自定義轉(zhuǎn)換。轉(zhuǎn)換器是全局的,請謹慎使用。

//xml code
<layout ……>
    <data>
        <variable
            name="show"
            type="boolean" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        ……>
        <TextView
            android:visibility="@{show}"
            ……/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

//java code
object DbAdapter {
    @BindingConversion
    @JvmStatic
    fun setShowView(show: Boolean): Int {
        return if (show) {
            View.VISIBLE
        } else {
            View.GONE
        }
    }
}

2. 擴展語法

2.1 布局和綁定表達式

2.1.1 表達式語言

?表達式語言與托管代碼中的表達式非常相似。

2.1.1.1 Null 合并運算符

//傳統(tǒng)方式
android:text="@{user.displayName != null ? user.displayName : user.lastName}"

//Null 合并運算符方式
android:text="@{user.displayName ?? user.lastName}"

2.1.1.2 避免出現(xiàn) Null 指針異常
?生成的數(shù)據(jù)綁定代碼會自動檢查有沒有 null 值并避免出現(xiàn) Null 指針異常。例如,在表達式 @{user.name} 中,如果 user 為 Null,則為 user.name 分配默認值 null。如果引用 user.age,其中 age 的類型為 int,則數(shù)據(jù)綁定使用默認值 0。

2.1.1.3 視圖引用
?表達式可以通過語法(綁定類將 ID 轉(zhuǎn)換為駝峰式大小寫),按 ID 引用布局中的其他視圖。

//TextView 視圖引用同一布局中的 EditText 視圖
<EditText
        android:id="@+id/example_text"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"/>
    <TextView
        android:id="@+id/example_output"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{exampleText.text}"/>

2.1.1.4 集合
?為方便起見,可使用 [] 運算符訪問常見集合,例如數(shù)組、列表、稀疏列表和映射。

<data>
        <import type="java.util.List"/>
        <variable name="list" type="List&lt;String>"/>
        <variable name="index" type="int"/>
    </data>
    …
    android:text="@{list[index]}"

2.1.1.5 字符串字面量

//可以使用單引號括住特性值,這樣就可以在表達式中使用雙引號
android:text='@{map["firstName"]}'

//也可以使用雙引號括住特性值。如果這樣做,則還應(yīng)使用反單引號 ` 將字符串字面量括起來
android:text="@{map[`firstName`]}"

2.1.1.6 資源

//簡單
android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"

//提供參數(shù)來評估格式字符串和復(fù)數(shù)形式
android:text="@{@string/nameFormat(firstName, lastName)}"
2.1.2 事件處理

?通過數(shù)據(jù)綁定,您可以編寫從視圖分派的表達式處理事件(例如,onClick() 方法)。

2.1.2.1 方法引用

//xml code
<layout ……>
    <data>
        <variable
            name="click"
            type="com.kejiyuanren.jetpack.databinding.ClickHandler" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        ……>
        <TextView
            android:onClick="@{click::onBtnClick}"
            ……/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

//java code
class ClickHandler {
    fun onBtnClick(view: View) {
        Log.d(TAG, "onBtnClick: ")
    }
}

2.1.2.2 監(jiān)聽器綁定
?監(jiān)聽器綁定是在事件發(fā)生時運行的綁定表達式。它們類似于方法引用,但允許運行任意數(shù)據(jù)綁定表達式。

//總有一款適合你
android:onClick="@{() -> presenter.onSaveClick(task)}"
android:onClick="@{(view) -> presenter.onSaveClick(task)}"
android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"
android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"
2.1.3 導(dǎo)入、變量和包含

2.1.3.1 導(dǎo)入
?通過導(dǎo)入功能,您可以輕松地在布局文件中引用類,就像在托管代碼中一樣??梢栽?data 元素使用多個 import 元素,也可以不使用。

<data>
        <import type="com.kejiyuanren.jetpack.databinding.View"
            alias="UnitView"/>  //類型別名,防止與下面的沖突
        <import type="android.view.View"/>    //引入View
    </data>

<TextView
       android:text="@{user.lastName}"
       android:text="@{((User)(user.connection)).lastName}"  //類型強轉(zhuǎn)
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>  //使用View

2.1.3.2 變量
?您可以在 data 元素中使用多個 variable 元素。

2.1.3.3 包含
?通過使用應(yīng)用命名空間和特性中的變量名稱,變量可以從包含的布局傳遞到被包含布局的綁定。注意:數(shù)據(jù)綁定不支持 include 作為 merge 元素的直接子元素。

//activity.xml
<layout ……>
    <data>
        <variable
            name="user"
            type="com.kejiyuanren.jetpack.databinding.ViewModel" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        ……>
        <TextView
            android:text="@{user.userName}"
            …… />
        <include
            layout="@layout/layout_title_append"
            app:user="@{user}"
            ……/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

//layout_title_append.xml
<layout ……>
    <data>
        <variable
            name="user"
            type="com.kejiyuanren.jetpack.databinding.ViewModel" />
    </data>
    <TextView
        android:text="@{user.userName.toUpperCase()}"
        ……>
    </TextView>
</layout>

2.2 可觀察的數(shù)據(jù)對象

?可觀察性是指一個對象將其數(shù)據(jù)變化告知其他對象的能力。通過數(shù)據(jù)綁定庫,您可以讓對象、字段或集合變?yōu)榭捎^察。

2.2.1 可觀察字段

在創(chuàng)建實現(xiàn) Observable 接口的類時要完成一些操作,但如果您的類只有少數(shù)幾個屬性,這樣操作的意義不大。字段設(shè)為可觀察字段:ObservableXXX。

//數(shù)據(jù)模型
class ViewModel {
    val userName = ObservableField<String>()
}

//觀察更新
        val userModel = ViewModel()
        userModel.userName.set("keyijiyuanren-1")
        binding.user = userModel

        binding.click = ClickHandler(object : ClickListener{
            override fun onClick() {
                userModel.userName.set("replace = $count")
            }
        })
2.2.2 可觀察對象

實現(xiàn) Observable 接口的類允許注冊監(jiān)聽器,以便它們接收有關(guān)可觀察對象的屬性更改的通知。

//數(shù)據(jù)模型
class ViewModel : BaseObservable() {
    @get:Bindable
    var userName: String = ""
        set(value) {
            field = value
            notifyPropertyChanged(BR.userName)
        }
}

//觀察更新
        val userModel = ViewModel()
        userModel.userName = "keyijiyuanren-1"
        binding.user = userModel

        binding.click = ClickHandler(object : ClickListener{
            override fun onClick() {
                userModel.userName = "replace = $count"
            }
        })

2.3 數(shù)據(jù)雙向綁定

?雙向綁定可以在上面的 2.2.1 可觀察字段基礎(chǔ)上,在xml中使用語法:@={} 表示法(其中重要的是包含“=”符號)可接收屬性的數(shù)據(jù)更改并同時監(jiān)聽用戶更新。

//xml code
<CheckBox
    android:checked="@={checkModel.check}"
    …… />

//java code
class CheckModel {
    val check = ObservableBoolean(false)
}
2.3.1 使用自定義特性的雙向數(shù)據(jù)綁定

&emsp;最常見的雙向特性和更改監(jiān)聽器提供了雙向數(shù)據(jù)綁定實現(xiàn),可以將其用作應(yīng)用的一部分。如果希望結(jié)合使用雙向數(shù)據(jù)綁定和自定義特性,則需要使用 @InverseBindingAdapter@InverseBindingMethod 注釋。
?下面實現(xiàn)了SeekBar的透明度與進度隨動。

//xml code
<layout ……>
    <data>
        <variable
            name="defineAlpha"
            type="float  " />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        ……>
        <SeekBar
            app:okAlpha="@={defineAlpha}"
            …… />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

//java code
    //第三步:獲取到已經(jīng)更新了的defineAlpha數(shù)據(jù),并更新 okAlpha 的 BindingAdapter方法
    @BindingAdapter("okAlpha")
    @JvmStatic
    fun setOkAlpha(okBar: SeekBar, newValue: Float) {
        okBar.alpha = newValue
    }

    //第二步:滑動觸發(fā) okAlpha 的 InverseBindingAdapter方法調(diào)用,獲取屬性okAlpha的值,更新defineAlpha的數(shù)據(jù)
    @InverseBindingAdapter(attribute = "okAlpha")
    @JvmStatic
    fun getOkAlpha(okSeekBar: SeekBar): Float {
        return okSeekBar.progress / 100f
    }

    @BindingAdapter("app:okAlphaAttrChanged")
    @JvmStatic
    fun setListeners(
        okSeekBar: SeekBar,
        attrChange: InverseBindingListener
    ) {
        // Set a listener for click, focus, touch, etc.
        okSeekBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                //第一步:監(jiān)聽滑動,會觸發(fā) okAlphaAttrChanged 的屬性 okAlpha 的 InverseBindingAdapter方法
                attrChange.onChange()
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {

            }

            override fun onStopTrackingTouch(seekBar: SeekBar?) {

            }
        })
    }
2.3.2 轉(zhuǎn)換器

?如果綁定到 View對象的變量需要設(shè)置格式、轉(zhuǎn)換或更改后才能顯示,則可以使用 Converter 對象。較簡單。

2.3.3 使用雙向數(shù)據(jù)綁定的無限循環(huán)

?使用雙向數(shù)據(jù)綁定時,請注意不要引入無限循環(huán)。當用戶更改特性時,系統(tǒng)會調(diào)用使用@InverseBindingAdapter 注釋的方法,并且該值將分配給后備屬性。繼而調(diào)用使用 @BindingAdapter 注釋的方法,從而觸發(fā)對使用 @InverseBindingAdapter 注釋的方法的另一個調(diào)用,依此類推。
?因此,通過比較使用 @BindingAdapter 注釋的方法中的新值和舊值,可以打破可能出現(xiàn)的無限循環(huán)。

2.3.4 雙向特性

?平臺對部分控件提供對雙向數(shù)據(jù)綁定的內(nèi)置支持。比如 TextViewBindingAdapter。

2.4 布局綁定架構(gòu)組件

?數(shù)據(jù)綁定庫可與架構(gòu)組件(AndroidX 庫包含的架構(gòu)組件)無縫協(xié)作,進一步簡化界面的開發(fā)。在后面的ViewModel和LiveData中再展開。

3. DataBinding文件說明

3.1 綁定類路徑

3.1.1 JavaModel 視圖層

?參考 Jetpack ViewBinding。

3.1.2 JavaModel 數(shù)據(jù)層

?路徑:app/build/generated/source/kapt/buildTypes

綁定類 數(shù)據(jù)層 生成路徑

3.1.3 Layout文件

?參考 Jetpack ViewBinding。

3.2 綁定類作用

3.2.1 JavaModel 視圖層

?JavaModel 視圖層(抽象類),繼承自 ViewDataBinding,功能類似ViewBinding。參考 Jetpack ViewBinding。

3.2.2 JavaModel 數(shù)據(jù)層

?JavaModel 數(shù)據(jù)層,繼承自 視圖層,添加的數(shù)據(jù)綁定的功能。

  • BR:綁定屬性的字段。
  • DataBindingComponent:綁定類作用域。
  • DataBinderMapperImpl:
    • androidx.databinding 路徑下:全局緩存添加器。
    • com.xx.xx(包名)路徑下:全局緩存器。
  • XxxBindingImpl:綁定類的字段更新策略,綁定類的生成單例策略等。
3.2.3 Layout文件

?用于生成JavaModel(綁定類)。參考 Jetpack ViewBinding

4. DataBinding原理分析

4.1 布局綁定類生成

?參考 Jetpack ViewBinding。

4.2 數(shù)據(jù)綁定類生成

?參考 Jetpack ViewBinding

4.3 綁定功能的數(shù)據(jù)流向

?直接來個最全的吧。雙向綁定數(shù)據(jù)流向:更新數(shù)據(jù)刷新視圖 vs 更新視圖刷新數(shù)據(jù)。

?例子代碼:

//xml code
<layout ……>
    <data>
        <variable
            name="checkModel"
            type="com.kejiyuanren.jetpack.databinding.CheckModel  " />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        ……>
        <CheckBox
            android:checked="@={checkModel.check}"
            …… />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

//java code
class CheckModel {
    val check = ObservableBoolean(false)
}

//java 更新操作
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: ActivityDataBinding2Binding = DataBindingUtil.setContentView(
            this,
            R.layout.activity_data_binding2
        )

        //設(shè)置java模型
        var checkModel = CheckModel()
        binding.checkModel = checkModel

        binding.click = ClickHandler(object : ClickListener{
            override fun onClick() {
                //輔助button,點擊,執(zhí)行反向選擇設(shè)置
                checkModel.check.set(!checkModel.check.get())
            }
        })
    }

?流程圖示:


Jetpack DataBinding 數(shù)據(jù)流向 綁定數(shù)據(jù)更新

5.小結(jié)

?DataBinding 催生了 MVVM,代碼簡潔松耦合。JetPack-Compose 才是大Boss,比DB還DB。不過目前還沒有穩(wěn)定版,期待……

?

小編的博客系列

Jetpack 全家桶
?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容