DataBinding使用介紹


啟用DataBinding

  首先設置使用DataBinding,在app module的build.gradle中添加如下代碼即可:

android{
    ...
    dataBinding{
        enabled = true;
    }
}

布局綁定

  在使用DataBinding時就不能按照之前的方式來編寫布局文件了,布局文件的根布局應該是layout,layout中同時存放要綁定的數據及布局,如下:

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

    <data>
        <variable name="title" type="java.lang.String"/>
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{title}"/>
    </LinearLayout>
</Layout>

layout為根布局,data節點中存放數據,下面就是常見的布局文件。data中的variable標簽為變量,類似於我們定義了一個變量,name為變量名,type為變量全限定類型名,包括包名。布局中通過@{}來引用這個變量的值,{}中可以是任意java表達式,但不推薦使用過多代碼。

我們可以使用import語法來導入類,以及使用alias設置別名:

<data>
    <import type="java.lang.String"/>
    <import type="包名.User" alias="ExUser"/>
    <variable name="title" type="String"/>
    <variable name="User" type="ExUser"/>
    </data>

也可以使用default字段設置默認值:

<TextView android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{title, default=my_default}"/>

綁定數據

  在新建一個類似上述實例代碼中的DataBinding布局文件activity_main.xml之后,Gradle會根據布局創建一個ActivityMainBinding類,我們需要獲取該對象來綁定數據,使用DataBinding時,不需要再按照之前的setContentView的方式來設置布局到Activity中,應該通過DataBindingUtil#setContentView來設置,該方法會返回對應的DataBinding對象,例如我們創建的布局文件為activity_main,那么生成的就是ActivityMainBinding,我們可以通過data節點使用class關鍵字改變這種默認的名字:

<data class=".MainActivityBinding">
...
</data/

"."號表示當前包名,也可以使用全限定包名指定。然后是獲取綁定類:

override fun onCreate(savedInstanceState: Bundle?){
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    binding.lifecycleOwner = this
    binding.title = "Title"
}

我們先獲取 DataBinding 對象,然后設置 variable 數據,lifecycleOwner 適用於管理生命周期的方法,設置后 Databinding 可以感知到 Activity 的生命周期,保證數據在可見時才會更新,不可見時不會更新數據。
如果是在 Fragment/ListView/RecyclerView 中,我們可以通過下面的方法獲取 DataBinding:

binding = ActivityMainBinding.inflate(layoutInflater, null, false)

綁定普通數據

  DataBinding可以綁定普通數據對象(非Observable/LiveData),例如上述例子中綁定了一個String類型的數據。綁定普通數據我們只需要按照上述的代碼設置即可。

綁定可觀察數據

  綁定可觀察數據意味着當數據變化時UI會一起變化,綁定可觀察數據由三種方式:object,field,collections。

對單個變量的綁定:fields

  對於一些數據類,如果我們不想繼承BaseObservable或者只需要其中幾個字段可觀察,那么可以使用這種方式來創建可觀察數據:

class User{
    var age = ObservableInt()
    var name = ObservableField<String>()
}

對於基本類型和Parcelable我們可以直接使用對應的包裝類:

  • ObservableBoolean
  • ObservableByte
  • ObservableChar
  • ObservableShort
  • ObservableInt
  • ObservableLong
  • ObservableFloat
  • ObservableDouble
  • ObservableParcelable

引用類型使用帶有泛型參數的ObservableField類來創建

var name = ObservableField<String>()

泛型參數為數據類型

對集合的綁定:collections

我們同樣可以在布局中綁定集合中的某個元素,當集合中的數據發生變化后會同步更新到UI

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <data>
        <import type="androidx.databinding.ObservableMap"/>
        <import type="androidx.databinding.ObservableList"/>
        <variable name="map" type="ObservableMap&lt;String, Object"/>
        <variable name="list" type="ObservableList&lt;Object"/>
    </data>
    ...
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{String.valueOf(map.count)}" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{String.valueOf(list[0])}" />
</layout>

綁定數據到UI中

val map = ObservableArrayMap<String, Any>.apply(){put("count", 0)}
binding.map = map
val list = ObservableArrayList<Any>().apply{add(0)}
binding.list = list

對於List來說,可以直接使用[]運算符(list[0])獲取對應位置的元素。而Map就很有趣了,可以使用.運算符直接獲取key對應的value:map.count,這還是很有意義的,我們如果不想定義一個數據實體,可以直接使用map替代。

綁定對象:objects

這是最常用的一種方式,需要綁定的數據實體類繼承BaseObservable:

class Person : BaseObservable(){
    @get:Bindable
    var country: String = ""
        set(value){
            field = value
            notifyPropertyChanged(BR.country)
        }
    
    @get:Bindable
    var sex: String = ""
        set(value){
            field = value
            notifyPropertyChanger(BR.sex)
        }
}

首先在需要支持可觀察的數據上添加@get:Bindable注解,然后重寫set方法,在其中調用notifyPropertyChanged方法表示更新該數據,BR是自動生成的,包名跟當前報名一致,會根據Bindable注解的變量生成對應的值;也可以調用notifyChange()方法更新所有數據。

綁定LiveData

  LiveData目前也支持數據綁定,綁定方式跟上述介紹的一樣:

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <data>
        <variable name="desc"
            type="androidx.lifecycle.MutableLiveData&lt;String>" />
    </data>
...
    <TextView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
           android:layout_gravity="center_vertical|end"
           android:textSize="18sp"
           android:text="@{desc}" />
</layout>

我們可以直接將LiveData賦值給text,然后綁定數據:

val desc = MutableLiveData<String>()
binding.desc = desc

需要注意的是,老版本的Gradle是不支持LiveData的綁定的,需要更新到Gradle3.4及以上。另外使用LiveData有個顯示,更新到LiveData數據時必須在主線程才行。

雙向綁定

上述的單向綁定是數據變化后更新UI,而雙向綁定是指其中任意一個變化后都會同步更新到另一個。雙向綁定使用@={}表達式來實現:

    <data>
...
   <variable name="input" type="androidx.databinding.ObservableField&lt;String"/>
    </data>
...
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={input}"/>

事件綁定

事件綁定其實跟數據綁定一樣,本質上就是將監聽器對象綁定到UI元素上:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
    <data class="">
    ...
        <variable
            name="handler"
            type="com.demo.jetpack.MainActivity.EventHandler"/>
    </data>
    ...
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:onClick="@{handler::onToastBtnClick}"
        android:text="ToastClick"
</layout>

然后我們寫好監聽事件,綁定到binding中即可

class MainActivity : AppCompatActivity(){
    override fun onCreate(savedInstanceState: Bundle?){
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        ...
        binding.handler = EventHandler()
    }
    
    ...
    inner class EventHandler{
        fun onToastBtnClick(v: View){
            Toast.makeText(this@MainActivity, "Click", Toast.LENGTH_SHORT).show()
        }
    }
}

自定義參數綁定: BindingAdapter

目前已支持的雙向綁定的列表如下:

除了上述的參數外,我們也可以使用BindingAdapter創建自定義參數

例如我們需要使用Glide加載網絡圖片,可以先創建一個使用了BindingAdapter注解的函數,注解中的字段為參數名,函數的第一個參數必須為目標View或者其子類,因此使用Kotlin時我們可以定義為擴展函數,這樣使用很方便。

@BindingAdapter("imageUrl")
fun ImageView.loadImage(url: String)= Glide.with(this.context).load(url).into(this)

然后我們就可以在布局代碼中直接使用該參數加載圖片

<ImageView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:layout_marginTop="10dp"
    imageUrl="@{imageUrl}"
    android:layout_gravity="center_horizontal"/>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM