Android DataBinding (一) 基本用法

Android DataBinding (一) 基本用法 (本文)
Android DataBinding (二) 事件處理
Android DataBinding (三) Observable
Android DataBinding (四) 自定義屬性
Android DataBinding (五) 自定義 View 的雙向綁定
Android DataBinding (六) EditText 綁定 TextChangedListener 和 FocusChangeListener

概述

2015 年的 I/O 大會(huì)上坯约,Google 發(fā)布了官方的數(shù)據(jù)綁定框架 Data Binding Library壶辜,使得官方原生支持 MVVM。

Data Binding 是把數(shù)據(jù)直接綁定到 XML 文件上,并能實(shí)現(xiàn)自動(dòng)刷新。

Data Binding 減少了代碼的耦合性,一些如 findViewById试伙、setText 之類的操作都可以通過綁定實(shí)現(xiàn)。

環(huán)境配置

環(huán)境配置非常簡(jiǎn)單于样,只要在 build.gradle 文件里面定義一下代碼即可

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

一個(gè)簡(jiǎn)單的例子

  1. 首先疏叨,定義一個(gè) Java Bean
public class User {

    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
  1. 然后定義 Layout 文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="user"
            type="com.example.tianjf.myapplication.User" />
    </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="@{user.name}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(user.age)}" />
    </LinearLayout>
</layout>

Layout 文件和之前有什么不同呢?

首先穿剖,在最外層再套一層 <layout></layout> 標(biāo)簽蚤蔓。

然后,在 layout 標(biāo)簽下面定義 <data></data> 標(biāo)簽糊余。
data 標(biāo)簽下面的 variable 定義數(shù)據(jù)綁定用的實(shí)體類秀又。這個(gè)實(shí)體是從外部傳進(jìn)來的(具體怎么傳下文再講)。
type 里面是完整的帶包名的類贬芥,
name 自定義一個(gè)名稱吐辙,下面具體綁定的時(shí)候就是用的這個(gè)名稱。

最后蘸劈,用 @{} 來把數(shù)據(jù)綁定到 UI 上昏苏。
@{user.name} 把 name 屬性綁定到第一個(gè) TextView 上。
@{String.valueOf(user.age)} 把 age 屬性綁定到第二個(gè) TextView 上威沫。這里 age 是 int 類型的捷雕,所以需要把它轉(zhuǎn)化成 String 類型。由于 String 是屬于 java.lang 下面的壹甥,所以不需要 import救巷。java.lang 以外的類是需要 import 的(具體怎么 import 下文再講)。

  1. 數(shù)據(jù)綁定
    之前的 Layout 文件的定義會(huì)默認(rèn)生成一個(gè)數(shù)據(jù)綁定類句柠,這個(gè)數(shù)據(jù)綁定類的名稱默認(rèn)和 Layout 文件的類名有關(guān)浦译。比如 activity_main.xml 會(huì)生成 ActivityMainBinding.java 文件。

我們來看看代碼

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setUser(new User("Jack", 10));
    }
}

用 DatabindingUtil.setContentView() 替換之前的 setContentView()溯职,返回值是自動(dòng)生成的 ActivityMainBinding精盅,然后調(diào)用 setUser 方法把 User 實(shí)例綁定到 XML 文件中去。

這樣谜酒,運(yùn)行之后就可以看到 User 的信息被顯示到了畫面上了叹俏。

生成的 Binding 類的獲取方式

上面例子中由于是 Activity 的 Layout 文件,所以使用了 DataBindingUtil.setContentView 來獲取僻族。

除了上面的方法粘驰,還可以通過 inflate 獲取屡谐。

MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());

如果是在 ListView 或者 RecyclerView 的 adapter 中

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
//or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

控制自動(dòng)生成類的生成方式

默認(rèn)情況下,會(huì)根據(jù) XML 文件的名稱(具體規(guī)則上文已經(jīng)提及)在 <package name>.databinding 目錄下生成文件蝌数。比如 package 名為 com.example.myapplication愕掏,那么會(huì)在 com.example.myapplication.databinding 下面生成文件。

生成的文件的名稱也可以自定義顶伞。

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

這樣的話饵撑,就會(huì)在 com.example.myapplication.databinding 下面生成 MainBinding 的文件。

生成的文件的路徑也可以自定義唆貌。
如果想直接在 package 下面生成

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

加一個(gè) . 就會(huì)在 com.example.myapplication 下面生成 MainBinding 的文件滑潘。

當(dāng)然,不想使用 package 名锨咙,想自己自定義路徑语卤,也是可以的,寫全你想要的路徑即可

<data class="com.example.MainBinding">
    ...
</data>

import

當(dāng)在 XML 中數(shù)據(jù)綁定的時(shí)候蓖租,用到了 java.lang 之外的類粱侣,必須在 data 標(biāo)簽下面 import羊壹。
比如想控制 View 的顯示和隱藏蓖宦。

<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@{user.name}"
  android:visibility="@{user.showName ? View.VISIBLE : View.GONE}" />

由于用到了 View 類,所以必須 import油猫。

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

variable 中用到的類也可以先 import 在使用稠茂,其實(shí)和 Java 是一樣的。

<data>
    <import type="com.example.tianjf.myapplication.User" />
    <variable
        name="user"
        type="User" />
</data>

如果類名相同情妖,package 名不相同睬关,上面的寫法就會(huì)出現(xiàn) type 不知道指定哪個(gè)類。但是別擔(dān)心毡证,可以用別名解決电爹。

<data>
    <import type="com.example.tianjf.myapplication.User" alias="User1" />
    <import type="com.example.tianjf.User" alias="User2" />
    <variable
        name="user1"
        type="User1" />
    <variable
        name="user2"
        type="User2" />
</data>

import 的類型可以用到 variable 中

    <data>
        <import type="com.example.tianjf.myapplication.User" />
        <import type="java.util.List"/>
        <variable name="user" type="User"/>
        <variable name="userList" type="List<User>"/>
    </data>

import 的類型可以用到表達(dá)式中

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

import 的類型可以調(diào)用它的 static 變量和 static 方法

<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"/>

include

當(dāng) layout 文件中用到 include 的時(shí)候,variable 也可以傳到 include 的 layout 文件中繼續(xù)使用

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

Null Safe

DataBinding 是 Null Safe 的料睛,比如下列代碼

<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@{user.name}"

如果 user 為 null丐箩,@{user.name} 也將為 null,并不會(huì)出現(xiàn) NullPointerException恤煞。

表達(dá)式的使用

DataBinding 的時(shí)候可以指定綁定傳進(jìn)來的值屎勘,也可以使用表達(dá)式達(dá)到各種效果!

前面提到的控制 View 的顯示和隱藏

<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@{user.name}"
  android:visibility="@{user.showName ? View.VISIBLE : View.GONE}" />

?? 操作符

android:text="@{user.displayName ?? user.lastName}"

如果不為 null居扒,則選取 ?? 左邊的概漱,如果為 null,則選取 ?? 右邊的喜喂,相當(dāng)于以下代碼

android:text="@{user.displayName != null ? user.displayName : user.lastName}"

集合的使用

<data>
    <import type="android.util.SparseArray"/>
    <import type="java.util.Map"/>
    <import type="java.util.List"/>
    <variable name="list" type="List<String>"/>
    <variable name="sparse" type="SparseArray<String>"/>
    <variable name="map" type="Map<String, String>"/>
</data>
…
android:text="@{list[0]}"
…
android:text="@{sparse[0]}"
…
android:text="@{map['key']}"

Resources 的使用

DataBinding 的時(shí)候也可以使用 resources

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

Format strings 也可以使用瓤摧。
比如下面的 string

<string name="name">My name is %s</string>

可以使用 String.format 傳入?yún)?shù)

android:text="@{String.format(@string/name,user.name)}"

也可以這樣寫

android:text="@{@string/name(user.name)}"

雙向綁定

前面介紹的都是單向綁定竿裂,即 ViewModel 的值綁定到 UI 上。如果希望 UI 的變更也反應(yīng)到 ViewModel姻灶,那么就需要雙向綁定了铛绰。其實(shí)雙向綁定很簡(jiǎn)單,只需要加個(gè) = 就好了产喉。

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={viewModel.firstName}"/>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捂掰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子曾沈,更是在濱河造成了極大的恐慌这嚣,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件塞俱,死亡現(xiàn)場(chǎng)離奇詭異姐帚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)障涯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門罐旗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人唯蝶,你說我怎么就攤上這事九秀。” “怎么了粘我?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵鼓蜒,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我征字,道長(zhǎng)都弹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任匙姜,我火速辦了婚禮畅厢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘氮昧。我一直安慰自己框杜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布郭计。 她就那樣靜靜地躺著霸琴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪昭伸。 梳的紋絲不亂的頭發(fā)上梧乘,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼选调。 笑死夹供,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的仁堪。 我是一名探鬼主播哮洽,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼弦聂!你這毒婦竟也來了鸟辅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤莺葫,失蹤者是張志新(化名)和其女友劉穎匪凉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捺檬,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡再层,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了堡纬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片聂受。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖烤镐,靈堂內(nèi)的尸體忽然破棺而出蛋济,到底是詐尸還是另有隱情,我是刑警寧澤职车,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布瘫俊,位于F島的核電站鹊杖,受9級(jí)特大地震影響悴灵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜骂蓖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一积瞒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧登下,春花似錦茫孔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至畔濒,卻和暖如春剩晴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工赞弥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留毅整,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓绽左,卻偏偏與公主長(zhǎng)得像悼嫉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拼窥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容