dataBinding數(shù)據(jù)綁定(一)

編譯環(huán)境

要將應(yīng)用配置為使用數(shù)據(jù)綁定醋旦,請(qǐng)?jiān)趹?yīng)用模塊的build.gradle文件中添加dataBinding元素:

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

使用數(shù)據(jù)綁定庫(kù)

數(shù)據(jù)綁定的布局文件以根標(biāo)記layout開(kāi)頭,后跟data元素和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>
        <variable
            name="user"
            type="com.jetpackdemo.User" />
    </data>

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

        <TextView
            android:id="@+id/tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

data中使用了包名為com.jetpackdemoUser文件,并為此對(duì)象設(shè)置了name:user署惯。
TextView中:android:text="@{user.name}"表示為TextView設(shè)置username屬性值。
完成布局文件后,系統(tǒng)會(huì)為每一個(gè)布局文件生成一個(gè)綁定類,默認(rèn)情況下衫嵌,類名基于布局文件的名稱,將xml文件的名稱轉(zhuǎn)換為駝峰大小寫彻秆,并在末尾添加Binding一詞楔绞。

lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.user = User("hello")
    }

如果在FragmentListViewRecyclerView適配器中使用數(shù)據(jù)綁定唇兑,則可以使用DataBindingUtilinflate方法:

val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)

布局表達(dá)式

可以在布局文件的使用一下運(yùn)算符和關(guān)鍵字:

  • 算術(shù)運(yùn)算符+ - * / %
  • 字符串連接運(yùn)算符 +
  • 邏輯運(yùn)算符 && ||
  • 二元運(yùn)算符 & | ^
  • 一元運(yùn)算符 + - 酒朵! ~
  • 移位運(yùn)算符 >> >>> <<
  • 比較運(yùn)算符 == > < >= <=(<需要轉(zhuǎn)義為&lt;)
  • instanceof
  • 分組運(yùn)算符 ()
  • 字面量運(yùn)算符-字符、字符串扎附、數(shù)字蔫耽、null
  • 類型轉(zhuǎn)換
  • 方法調(diào)用
  • 字段訪問(wèn)
  • 數(shù)組訪問(wèn)[ ]
  • 三元運(yùn)算符 ?:
缺少的布局表達(dá)式
  • this
  • super
  • new
  • 顯式泛型調(diào)用
Null合并運(yùn)算符
android:text="@{user.name ?? user.sex}"

如果左邊運(yùn)算不為null則選擇左邊運(yùn)算,否則選擇右邊運(yùn)算帕棉。

屬性引用
android:text="@{user.name}"
避免出現(xiàn)Null指針異常

生成的數(shù)據(jù)綁定代碼會(huì)自動(dòng)檢查有沒(méi)有null值并避免出現(xiàn)null指針異常针肥。如果在表達(dá)式中Stringnull則分配默認(rèn)值null饼记。

集合表達(dá)式

為了方便訪問(wèn)香伴,可使用[ ]運(yùn)算符訪問(wèn)常見(jiàn)集合慰枕,例如數(shù)組、列表即纲、稀疏列表和映射具帮。

<data>
         <import type=”android.util.SparseArray"/>
         <import type="java.util.Map"/>
         <import type="java.util.List"/>
         <variable name="list" type="List&lt;String>"/>
         <variable name="sparse" type="SparseArray&lt;String>"/>
         <variable name="map" type="Map&lt;String,String>/>
         <variable name="index" type="int"/>
         <variable name="key" type="String"/> 
</data>
...
android:text="@{list[index]}"
...
android:text="@{sparse[index]}"
...
android:text="@{map[key]}"

在集合中,必須使用轉(zhuǎn)義<字符低斋。例如:不要寫成List<String>形式蜂厅,而是必須寫成List&lt;String>

獲取map中的值
android:text='@{map.get("name")}'

事件處理

通過(guò)數(shù)據(jù)綁定膊畴,您可以編寫從視圖分派的表達(dá)式處理事件(例如:onClick()方法)掘猿。事件名稱由監(jiān)聽(tīng)器方法的名稱確定。
可以使用以下機(jī)制處理事件:

方法引用:在表達(dá)式中唇跨,您可以引用符合監(jiān)聽(tīng)器方法簽名的方法稠通,當(dāng)表達(dá)式求值結(jié)果為方法引用時(shí),數(shù)據(jù)綁定會(huì)將方法引用和所有者對(duì)象封裝到監(jiān)聽(tīng)器中买猖,并在目標(biāo)視圖上設(shè)置該監(jiān)聽(tīng)器改橘。如果表達(dá)式的求值結(jié)果為 null,則數(shù)據(jù)綁定不會(huì)創(chuàng)建監(jiān)聽(tīng)器玉控,而是設(shè)置null監(jiān)聽(tīng)器飞主。
監(jiān)聽(tīng)器綁定:這些是在事件發(fā)生時(shí)進(jìn)行求值的lambda表達(dá)式。數(shù)據(jù)綁定始終會(huì)創(chuàng)建一個(gè)要在視圖上設(shè)置的監(jiān)聽(tīng)器高诺。事件被分派后碌识,監(jiān)聽(tīng)器會(huì)對(duì)lambda表達(dá)式進(jìn)行求值。

方法引用

一個(gè)主要優(yōu)點(diǎn)是表達(dá)式在編譯時(shí)進(jìn)行處理虱而,因此筏餐,如果該方法不存在或其簽名不正確,則會(huì)收到編譯時(shí)錯(cuò)誤薛窥。

    class MyHandlers {
        fun onClickFriend(view: View) { ... }
    }
<?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
       <data>
           <variable name="handlers" type="com.example.MyHandlers"/>
           <variable name="user" type="com.example.User"/>
       </data>
       <LinearLayout
           android:orientation="vertical"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.firstName}"
               android:onClick="@{handlers::onClickFriend}"/>
       </LinearLayout>
    </layout>

方法引用中的簽名必須和方法中的簽名保持一致,并且參數(shù)也保持一致胖烛,不能自定義參數(shù)。

監(jiān)聽(tīng)器綁定

監(jiān)聽(tīng)器綁定是在事件發(fā)生時(shí)運(yùn)行的綁定表達(dá)式诅迷。它們類似于方法引用佩番,但允許您運(yùn)行任意數(shù)據(jù)綁定表達(dá)式。此功能適用于 Gradle 2.0 版及更高版本的 Android Gradle 插件罢杉。
在方法引用中趟畏,方法的參數(shù)必須與事件監(jiān)聽(tīng)器的參數(shù)匹配。在監(jiān)聽(tīng)器綁定中滩租,只有您的返回值必須與監(jiān)聽(tīng)器的預(yù)期返回值相匹配(預(yù)期返回值無(wú)效除外)赋秀。

    class Presenter {
        fun onSaveClick(task: Task){}
    }

然后利朵,您可以將點(diǎn)擊事件綁定到 onSaveClick() 方法

<?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
        <data>
            <variable name="task" type="com.android.example.Task" />
            <variable name="presenter" type="com.android.example.Presenter" />
        </data>
        <LinearLayout 
               android:layout_width="match_parent" 
               android:layout_height="match_parent">
               <Button 
                    android:layout_width="wrap_content" 
                    android:layout_height="wrap_content"
                    android:onClick="@{() -> presenter.onSaveClick(task)}" />
        </LinearLayout>
    </layout>

如果監(jiān)聽(tīng)的事件返回類型不是void的值,那么表達(dá)式也必須返回相同類型的值(比如長(zhǎng)按事件返回值是boolean)猎莲。

fun onSaveClick(task: Task): Boolean{}

從以上說(shuō)明可以看出绍弟,方法引用更適合簡(jiǎn)單的事件處理,并且方法不需要自定義參數(shù)著洼。監(jiān)聽(tīng)器則更適合復(fù)雜的事件處理樟遣,方法可以自定義參數(shù)。

避免使用復(fù)雜的監(jiān)聽(tīng)器

監(jiān)聽(tīng)器表達(dá)式功能非常強(qiáng)大身笤,可以使您的代碼非常易于閱讀豹悬。另一方面,包含復(fù)雜表達(dá)式的監(jiān)聽(tīng)器會(huì)使您的布局難以閱讀和維護(hù)液荸。這些表達(dá)式應(yīng)該像將可用數(shù)據(jù)從界面?zhèn)鬟f到回調(diào)方法一樣簡(jiǎn)單瞻佛。您應(yīng)該在從監(jiān)聽(tīng)器表達(dá)式調(diào)用的回調(diào)方法中實(shí)現(xiàn)任何業(yè)務(wù)邏輯。

導(dǎo)入娇钱、變量和包含

導(dǎo)入

通過(guò)導(dǎo)入功能伤柄,您可以輕松地在布局文件中引用類,就像在托管代碼中一樣忍弛。您可以在 data 元素使用多個(gè) import 元素响迂,也可以不使用。以下代碼示例將View類導(dǎo)入到布局文件中:

<data>
        <import type="android.view.View"/>
    </data>

上述方法中導(dǎo)入了View類细疚,可以引用View的屬性蔗彤,比如設(shè)置顯示:

android:visibility="@{user.man? View.VISIBLE : View.GONE}"
類型別名

當(dāng)類名有沖突時(shí),其中一個(gè)類可使用別名重命名疯兼。以下示例將com.example.real.estate軟件包中的View類重命名為Vista

<import type="android.view.View"/>
    <import type="com.example.real.estate.View"
            alias="Vista"/>
導(dǎo)入其他類
<data>
        <import type="com.example.User"/>
        <import type="java.util.List"/>
        <variable name="user" type="User"/>
        <variable name="userList" type="List&lt;User>"/>
    </data>

還可以通過(guò)使用導(dǎo)入的類型來(lái)對(duì)表達(dá)式的一部分進(jìn)行類型轉(zhuǎn)換然遏。以下示例將connection屬性強(qiáng)制轉(zhuǎn)換為類型User

<TextView
       android:text="@{((User)(user.connection)).lastName}"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>

在表達(dá)式中引用靜態(tài)字段和方法時(shí),也可以使用導(dǎo)入的類型吧彪。以下代碼會(huì)導(dǎo)入MyStringUtils類待侵,并引用其 capitalize方法:

<data>
        <import type="com.example.MyStringUtils"/>
        <variable name="user" type="com.example.User"/>
    </data>
    …
    <TextView
       android:text="@{MyStringUtils.capitalize(user.lastName)}"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
包含

通過(guò)使用應(yīng)用命名空間和特性中的變量名稱,變量可以從包含的布局傳遞到被包含布局的綁定姨裸。以下示例展示了來(lái)自 name.xml 和 contact.xml 布局文件的被包含 user 變量:

<?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:bind="http://schemas.android.com/apk/res-auto">
       <data>
           <variable name="user" type="com.example.User"/>
       </data>
       <LinearLayout
           android:orientation="vertical"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <include layout="@layout/name"
               bind:user="@{user}"/>
           <include layout="@layout/contact"
               bind:user="@{user}"/>
       </LinearLayout>
    </layout>

數(shù)據(jù)綁定不支持 include 作為 merge 元素的直接子元素秧倾。例如,以下布局不受支持:

<?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:bind="http://schemas.android.com/apk/res-auto">
       <data>
           <variable name="user" type="com.example.User"/>
       </data>
       <merge><!-- Doesn't work -->
           <include layout="@layout/name"
               bind:user="@{user}"/>
           <include layout="@layout/contact"
               bind:user="@{user}"/>
       </merge>
    </layout>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末傀缩,一起剝皮案震驚了整個(gè)濱河市那先,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赡艰,老刑警劉巖售淡,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡揖闸,警方通過(guò)查閱死者的電腦和手機(jī)揍堕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)汤纸,“玉大人衩茸,你說(shuō)我怎么就攤上這事《紫” “怎么了递瑰?”我有些...
    開(kāi)封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵祟牲,是天一觀的道長(zhǎng)隙畜。 經(jīng)常有香客問(wèn)我,道長(zhǎng)说贝,這世上最難降的妖魔是什么议惰? 我笑而不...
    開(kāi)封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮乡恕,結(jié)果婚禮上言询,老公的妹妹穿的比我還像新娘。我一直安慰自己傲宜,他們只是感情好运杭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著函卒,像睡著了一般辆憔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上报嵌,一...
    開(kāi)封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天虱咧,我揣著相機(jī)與錄音,去河邊找鬼锚国。 笑死腕巡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的血筑。 我是一名探鬼主播绘沉,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼豺总!你這毒婦竟也來(lái)了车伞?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤园欣,失蹤者是張志新(化名)和其女友劉穎帖世,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡日矫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年赂弓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哪轿。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡盈魁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出窃诉,到底是詐尸還是另有隱情杨耙,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布飘痛,位于F島的核電站珊膜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏宣脉。R本人自食惡果不足惜车柠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望塑猖。 院中可真熱鬧竹祷,春花似錦、人聲如沸塑陵。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)占遥。三九已至,卻和暖如春芬萍,著一層夾襖步出監(jiān)牢的瞬間柬祠,已是汗流浹背负芋。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蠕嫁,地道東北人毯盈。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓搂赋,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親脑奠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355