Jetpack 之 DataBinding 小白入手

聲明 : http://www.itdecent.cn/p/714062a9af75
目錄:

簡介
原理
使用方法

1,一節(jié)界面數(shù)據(jù)綁定(基礎(chǔ)使用)
2,二級界面的綁定
3,響應(yīng)事件
4,BindAdapter
5,RecycleView 綁定機制
6,雙向綁定

?? 簡介:

??DataBinding 是一種庫,借助該庫,可以使用聲明性格式(而非程序化地)將布局中的界面組件綁定到應(yīng)用中的數(shù)據(jù)源。簡單來說,就是幫我們實現(xiàn) view 和 data 綁定的工具.DataBinding 的出現(xiàn)讓布局文件承擔(dān)了部分原本屬于界面的工作,使頁面與布局之間的耦合度進(jìn)一步降低.
????:項目簡潔,可讀性高,部分與 ui 控件的代碼都在布局文件里完成.
????:不再需要 findViewById()
????:布局文件可以包含簡單的業(yè)務(wù)邏輯.ui 控件能夠直接與數(shù)據(jù)模型中的字段綁定,甚至能響應(yīng)用戶的交互.

?? 原理:

??先略過去吧....太復(fù)雜了....??????,就看看下面的使用方法吧.....

?? 使用方法:

?? 一級界面數(shù)據(jù)綁定
1,build.gradle
android {
    //....
    dataBinding {
        enabled = true
    }
}

??啟動綁定數(shù)據(jù)

2,創(chuàng)建 Person 對象
class Person(var name: String?, var age: Int, var sex: String?)
3,修改布局文件 activity_data_binding.xml

??在布局文件外層加入<layout>標(biāo)簽,可以手動添加,也可以將鼠標(biāo)移到文件的根目錄,單擊小燈泡的下來三角框,選中 Convert to data binding layout,AS會自動生成代碼.

image.png

<layout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   xmlns:app="http://schemas.android.com/apk/res-auto">

 <data>

 </data>

 <androidx.constraintlayout.widget.ConstraintLayout
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     tools:context=".DataBindingActivity">

 </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

??我們所做的修改是在 ui 布局的最外層加上一個 layout 的標(biāo)簽,并將命名空間 xmlns 從ConstraintLayout移到了<layout>標(biāo)簽中.這樣做的目的是,告訴 DataBinding 庫,我們要對該布局進(jìn)行綁定,此時,rebuild 該項目,DataBinding 庫會為我們生成綁定該布局文件所需要的類.

4,實例化布局

??有了 DataBinding 之后,就可以告別 findViewById()了,我們可以通過DataBindingUtil.setContentView()方法實例化布局文件,該方法返回實例化后布局文件對象,名字和布局文件的名字一樣,并在后面加上 Binding.

class DataBindingActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var activityDataBindingBinding: ActivityDataBindingBinding =
            DataBindingUtil.setContentView<ActivityDataBindingBinding>(
                this,
                R.layout.activity_data_binding
            )
    }
}

?? 比如,我的布局文件名字叫 activity_data_binding.xml ,布局文件對象叫 ActivityDataBindingBinding.

5,將數(shù)據(jù)傳遞到布局文件

??為了減輕 Activity 的工作量,讓布局文件也承擔(dān)一部分工作,所以要將 Person 對象傳遞到布局文件.具體做法如下
?? 首先在布局文件<data>標(biāo)簽中定義個布局變量<variable>,指定類型和名字,名字可以隨意定義.

    <data>
        <variable
            name="personD"
            type="com.mcy.test.model.Person" />
    </data>

??<data>標(biāo)簽 用于放置 ui 控件所需要的數(shù)據(jù),數(shù)據(jù)類型可以自定義,比如代碼中是的 Person 類,也可以是基本類型.

    <data>
        <variable  name="title"  type="String" />
    </data>

???? 然后在 Activty 中通過 setPersonD()方法,將 Person 對象傳遞給布局文件中對應(yīng)的布局變量.

        activityDataBindingBinding.personD = Person("張三", 30, "男")

?????? 綁定布局文件和成員變量

     <EditText
            android:text="@{personD.name}"/>

        <TextView
            android:text="@{personD.sex}"/>

?? 布局文件用@{} 表達(dá)式為控件賦值
????????在布局文件引用靜態(tài)類
??有時候我們需要在布局文件中引用一些 java/kotlin 工具類,幫助我們處理簡單的邏輯.

class Utils {
    companion object {
        @JvmStatic
        fun getStr(a: Int): String {
            return a.toString()
        }
    }
}

??我們可以再布局文件中通過<import> 標(biāo)簽導(dǎo)入靜態(tài)工具類

    <data>

        <import type="com.mcy.test.Utils" />
    <data>

??接著在控件中使用

        <TextView
            android:text="@{Utils.getStr(personD.age)}"/>
6,完整的布局和 Activty 文件
<?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>

      <import type="com.mcy.test.Utils" />

      <variable
          name="personD"
          type="com.mcy.test.model.Person" />
  </data>

  <androidx.constraintlayout.widget.ConstraintLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context=".DataBindingActivity">

      <EditText
          android:id="@+id/textView"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_marginTop="9dp"
          android:text="@{personD.name}"
          app:layout_constraintEnd_toEndOf="parent"
          app:layout_constraintStart_toStartOf="parent"
          app:layout_constraintTop_toTopOf="parent" />

      <TextView
          android:id="@+id/textView2"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_marginTop="7dp"
          android:text="@{Utils.getStr(personD.age)}"
          app:layout_constraintEnd_toEndOf="parent"
          app:layout_constraintStart_toStartOf="parent"
          app:layout_constraintTop_toBottomOf="@+id/textView" />


      <TextView
          android:id="@+id/textView3"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_marginTop="9dp"
          android:text="@{personD.sex}"
          app:layout_constraintEnd_toEndOf="parent"
          app:layout_constraintStart_toStartOf="parent"
          app:layout_constraintTop_toBottomOf="@+id/textView2" />
  </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
class DataBindingActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var activityDataBindingBinding: ActivityDataBindingBinding =
           DataBindingUtil.setContentView<ActivityDataBindingBinding>(
                this,
                R.layout.activity_data_binding
            )
        //單向
        activityDataBindingBinding.personD = Person("張三", 30, "男")
    }
}

運行截圖:


圖一.png
?? 二級界面的綁定

?? 在一級界面布局中,設(shè)置好布局變量personD之后,便可以接受來自 Activty 的數(shù)據(jù),進(jìn)而將數(shù)據(jù)和控件進(jìn)行綁定,不僅如此,布局變量personD同時也是命名空間 xmlns:app 的一個屬性,一級界面正是通過命名空間xmlns:app引用布局變量 personD ,將數(shù)據(jù)對象傳遞給二級頁面.具體代碼如下:
二級頁面 layout_second.xml
?? 將 sex 的 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">

   <data>

       <variable
           name="personD"
           type="com.mcy.test.model.Person" />
   </data>

   <androidx.constraintlayout.widget.ConstraintLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <TextView
           android:id="@+id/textView3"
           android:text="@{personD.sex}"
            ......./><!--省略部分代碼 -->
   </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

一級頁面 activity_data_binding.xml

<?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>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".DataBindingActivity">
          <!--省略部分代碼 -->
        <include
            android:id="@+id/in_3"
            layout="@layout/layout_second"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView2"
            app:personD="@{personD}" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

運行出來的截圖和圖一是一樣的啦,就粘貼過來啦??????

?? 響應(yīng)事件
1,編寫一個類,用于接受和響應(yīng) Button 的 onClick 事件.

命名為 HandleClickListener可以單獨寫一個文件,也可以寫在 Activity 中,作為內(nèi)部類.

    inner class HandleClickListener {
        fun showToast(view: View) {
            Toast.makeText(view.context, "哈哈哈", Toast.LENGTH_LONG).show()
        }
    }

??????**在定義事件方法名稱時需要注意:方法的名稱可以和原始函數(shù)名稱不一樣,方法參數(shù)和返回值必須和原始的回調(diào)函數(shù)保持一致。不然會報錯,比如:clickFirst(View view)必須要有view參數(shù),如果沒有會報錯.**????

2,在布局文件中定義并使用
<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>
        <variable
            name="handleC"
            type="com.mcy.test.DataBindingActivity.HandleClickListener" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".DataBindingActivity">
        <!--省略部分代碼 -->
        <Button
            android:id="@+id/button4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="7dp"
            android:onClick="@{handleC::showToast}"
            android:text="點我"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/in_3" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

?? 也可以用雙冒號android:onClick="@{handleC::showToast}"

3,在 Avtivity 中實例化HandleClickListener類
class DataBindingActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var activityDataBindingBinding: ActivityDataBindingBinding =
            DataBindingUtil.setContentView<ActivityDataBindingBinding>(
                this,
                R.layout.activity_data_binding
            )
        //監(jiān)聽
        activityDataBindingBinding.handleC = HandleClickListener()
      }
}

運行截圖


image.png
?? 自定義 BindingAdapter

?? 在 gradle 啟動 DataBinding 庫的時候,就會為我們生成所需要的各種類,其中包括大量針對 ui 控件的,名為 XXXBindingAdapter 的類,這些類中包含各種靜態(tài)方法,并且在這些靜態(tài)方法前都有@BindingAdapter 標(biāo)簽,標(biāo)簽中的別名對應(yīng)于 ui 控件在布局文件中的屬性.
?? 看個例子,TextView的 TextViewBindingAdapter 的部分源碼:

public class TextViewBindingAdapter {

    private static final String TAG = "TextViewBindingAdapters";
    @SuppressWarnings("unused")
    public static final int INTEGER = 0x01;
    public static final int SIGNED = 0x03;
    public static final int DECIMAL = 0x05;

    @BindingAdapter("android:text")
    public static void setText(TextView view, CharSequence text) {
        final CharSequence oldText = view.getText();
        if (text == oldText || (text == null && oldText.length() == 0)) {
            return;
        }
        if (text instanceof Spanned) {
            if (text.equals(oldText)) {
                return; // No change in the spans, so don't set anything.
            }
        } else if (!haveContentsChanged(text, oldText)) {
            return; // No content changes, so don't set anything.
        }
        view.setText(text);
    }
    //........
}

?? Databinding 庫以靜態(tài)方法的形式為 ui 控件的各個屬性綁定了響應(yīng)的代碼.若開發(fā)人員在 UI控件的屬性中使用了表達(dá)式,那么當(dāng)布局文件被渲染時,屬性所綁定的方法會被自動調(diào)用.

?? 比如,當(dāng) TextView 被渲染時,android:text屬性會自動調(diào)用 TextViewBindingAdapter.setText()方法.UI控件通過簡單的屬性設(shè)置,便可以在布局文件中調(diào)用所綁定的方法.

那么我們就來自定義一個處理圖片的 BindAdapter 類:
1, 添加 Glide 庫
    implementation 'com.github.bumptech.glide:glide:4.12.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
2, 添加網(wǎng)絡(luò)權(quán)限
 <uses-permission android:name="android.permission.INTERNET" />
3, 編寫處理圖片的 BindAdapter 類
class ImageViewBindingAdapter {
    companion object{
    @JvmStatic
    @BindingAdapter("imageV")
    fun setImage(image: ImageView, imageUrl: String?) {
        if (!TextUtils.isEmpty(imageUrl)) {
            Glide.with(image.context).load(imageUrl).into(image)
        } else {
            image.setImageResource(R.mipmap.ic_launcher)
            }
        }
    }
}

?? BindAdapter中的方法均為靜態(tài)方法,第 1 個參數(shù)是調(diào)用者本身,即 ImageView,第 2 個參數(shù)是布局文件在調(diào)用該方法傳遞過來的參數(shù).在靜態(tài)方法前面需要加入@BindingAdapter()標(biāo)簽,并為該方法起一個別名,此處為 imageV.布局文件正式通過別名來調(diào)用方法的.

4, 修改布局文件

?? 在布局文件定義 String ,傳遞圖片地址.

        <variable
            name="internetImageUrl"
            type="String" />

?? ImageView調(diào)用

<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>
        <variable
            name="internetImageUrl"
            type="String" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
  
        <ImageView
            android:id="@+id/imageView"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="9dp"
            app:imageV="@{internetImageUrl}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/button4"
            tools:srcCompat="@tools:sample/avatars" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
5, Activity 中設(shè)置布局文件變量
class DataBindingActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var activityDataBindingBinding: ActivityDataBindingBinding =
            DataBindingUtil.setContentView<ActivityDataBindingBinding>(
                this,
                R.layout.activity_data_binding
            )
        //自定義 adapter
        activityDataBindingBinding.internetImageUrl =
            "https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3436121203,3749922833&fm=26&gp=0.jpg"
    }
}

運行截圖:


image.png

?? 在上面的示例中,我們做了接受網(wǎng)絡(luò)圖片地址的展示,如果還希望,在接受網(wǎng)絡(luò)圖片的時候,也能接受本地圖片資源作為參數(shù),這樣,當(dāng)網(wǎng)絡(luò)圖片地址為空的時候,則顯示本地圖片資源所制定的圖片.根據(jù)這個需求,我們優(yōu)化一下 BindAdapter

class ImageViewBindingAdapter {
    companion object {
        @JvmStatic
        @BindingAdapter(value = ["imageV", "defaultRes"], requireAll = false)
        fun setImage(image: ImageView, imageUrl: String?, imageResource: Int) {
            if (!TextUtils.isEmpty(imageUrl)) {
                Glide.with(image.context).load(imageUrl).into(image)
            } else {
                image.setImageResource(imageResource)
            }
        }
    }
}

?? 在@BindingAdapter標(biāo)簽中,方法參數(shù)以 value = ["", ""]的形式存在,變量 requireAll 作用是告訴 DataBinding 庫這些參數(shù)是否都要賦值,默認(rèn)是 true.

資源文件:

<?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>

        <variable
            name="internetImageUrl"
            type="String" />

        <variable
            name="imageRes"
            type="int" />
    </data>
        <!--省略部分代碼 ConstraintLayout -->
        <ImageView
            app:defaultRes="@{imageRes}"
            app:imageV="@{internetImageUrl}" />
        <!--省略部分代碼 ConstraintLayout -->
</layout>

Activity:

class DataBindingActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var activityDataBindingBinding: ActivityDataBindingBinding =
            DataBindingUtil.setContentView<ActivityDataBindingBinding>(
                this,
                R.layout.activity_data_binding
            )
        //自定義 adapter
        activityDataBindingBinding.internetImageUrl =
            "https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3436121203,3749922833&fm=26&gp=0.jpg"
        activityDataBindingBinding.imageRes = R.mipmap.ic_launcher
   }
}
?? RecycleView 綁定機制
1,布局文件
<?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>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".DataBindingActivity">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycle"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/imageView" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

?? RecycleView 的布局

2,item 布局 item_recycle.xml
<?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>

        <import type="com.mcy.test.Utils" />

        <variable
            name="personI"
            type="com.mcy.test.model.Person" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp">

        <TextView
            android:id="@+id/textView4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{personI.name}"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toLeftOf="@+id/textView5"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/textView5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{Utils.getStr(personI.age)}"
            app:layout_constraintLeft_toRightOf="@+id/textView4"
            app:layout_constraintRight_toLeftOf="@+id/textView6"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/textView6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{personI.sex}"
            app:layout_constraintLeft_toRightOf="@+id/textView5"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

?? RecycleView 的 item 布局文件,分別綁定不同的數(shù)據(jù).

3,編寫 Adapter
class RecycleViewAdapter(private val list: MutableList<Person>) :
    RecyclerView.Adapter<MyViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        return MyViewHolder(DataBindingUtil.inflate(
                LayoutInflater.from(parent.context), R.layout.item_recycle,parent,  false ))
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val personViewModel = list[position]
        holder.itemRecycleBinding.personI = personViewModel
    }

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

    inner class MyViewHolder(var itemRecycleBinding: ItemRecycleBinding) 
        : RecyclerView.ViewHolder(itemRecycleBinding.root) //.root 返回的是布局的最外層 ui 視圖
}

?? 編寫 Adapter 需要注意三個地方:
?? ?? 在 onCreateViewHolder()方法中,通過 DataBindingUtil.inflate()實例化布局.
?? ??在 onBindViewHolder 方法中,設(shè)置布局變量
?? ?? ItemRecycleBinding 是 DataBinding 為布局文件 item_recycle.xml 生成的對象

4,Activity 添加數(shù)據(jù)
class DataBindingActivity : AppCompatActivity() {
    private val list = mutableListOf<Person>()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var activityDataBindingBinding: ActivityDataBindingBinding =
            DataBindingUtil.setContentView<ActivityDataBindingBinding>(
                this,
                R.layout.activity_data_binding
            )
        //recycleview
        for (i in 1..100) {
            var personViewModel1 = Person("張三$i", i, "女")
            list.add(personViewModel1)
        }
        activityDataBindingBinding.recycle.layoutManager = LinearLayoutManager(this)
        activityDataBindingBinding.recycle.adapter = RecycleViewAdapter(list)
    }
}

運行截圖:


image.png
?? 雙向綁定
1,編寫PersonViewModel類
class PersonViewModel(name: String, age: Int, sex: String) {
    var name = ObservableField<String>()
    var age = ObservableField<Int>()
    var sex = ObservableField<String>()

    init {
        this.name.set(name)
        this.age.set(age)
        this.sex.set(sex)

    }
}

?? ObservableField<T> 關(guān)鍵字將普通對象包裝成可觀察對象,可以包裝基本類型,集合數(shù)組類型,自定義類型的數(shù)據(jù).當(dāng)數(shù)據(jù)發(fā)生變化時,界面所用的與之相關(guān)的數(shù)據(jù)會隨之刷新.

2,編寫布局文件
<?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>
      <!--省略部分代碼 ConstraintLayout -->

        <variable
            name="handleC"
            type="com.mcy.test.DataBindingActivity.HandleClickListener" />
        <variable
            name="personVM"
            type="com.mcy.test.model.PersonViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".DataBindingActivity">

        <EditText
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="9dp"
            android:text="@={personVM.name}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/button4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="7dp"
            android:onClick="@{handleC::showToast}"
            android:text="@{personVM.name}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/in_3" />
        <!--省略部分代碼 ConstraintLayout -->
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

?? android:text="@={personVM.name}" 采用@={}表達(dá)式完成雙向綁定
??

3,編寫 Activty
class DataBindingActivity : AppCompatActivity() {
    var personViewModel = PersonViewModel("張三",20,"女")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var activityDataBindingBinding: ActivityDataBindingBinding =
            DataBindingUtil.setContentView<ActivityDataBindingBinding>(
                this,
                R.layout.activity_data_binding
            )
      
        //雙向
        activityDataBindingBinding.personVM = personViewModel
      
    }

    inner class HandleClickListener {
        fun showToast(view: View) {
            Toast.makeText(view.context, personViewModel.name.get(), Toast.LENGTH_LONG).show()
        }
    }

}

運行圖片


嘿嘿嘿.gif

END

image.png
最后編輯于
?著作權(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)容