1. 程式人生 > >Android官方資料繫結框架DataBinding

Android官方資料繫結框架DataBinding

轉自:http://blog.csdn.net/qibin0506/article/details/47393725

今天來了解一下android最新給我們帶來的資料繫結框架——Data Binding Library。資料繫結框架給我們帶來了更大的方便性,以前我們可能需要在Activity裡寫很多的findViewById,煩人的程式碼也增加了我們程式碼的耦合性,現在我們馬上就可以拋棄那麼多findViewById。說到這裡,有人可能會有個疑問:我使用一些註解框架也可以不用findViewById啊,是的,但是註解註定要拖慢我們程式碼的速度,Data Binding則不會,官網文件說還會提高解析XML的速度

,最主要的Data Binding並不是單單減少了我們的findViewById,更多好處請往下看文章。

一、環境 
在開始使用新東西之前,我們需要稍微的配置一下環境,這裡要求你的Android Studio版本是1.3+,使用eclipse的同學暫時還沒有辦法使用該框架,請換用Android Studio。還有,在開始之前,請更新你的Support repository到最新的版本。 
萬事俱備,那我們就開始搭配環境!

新建一個project,在dependencies中新增以下依賴

classpath "com.android.databinding:dataBinder:1.0-rc1"

新建module,並且在module的build.gradle檔案中新增

apply plugin: 'com.android.application'
apply plugin: 'com.android.databinding'

ok,到現在為止,我們的環境就準備完畢了,下面我們就開始Data Binding的學習啦。

二、Data Binding嘗試 
在程式碼開始,我們並不直接進入新東西的講解,而且以一段程式碼展現Data Binding的魅力。 
首先我們需要一個java bean,很簡單,一個學生類。

public class Student {
    private String name;
    private String addr;

    public Student() {
    }

    public Student(String name, String addr) {
        this.name = name;
        this.addr = addr;
    }

    public String getName() {
        return name;
    }

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

    public String getAddr() {
        return this.addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }
}

再來看看我們佈局檔案怎麼寫:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="stu"
            type="org.loader.androiddatabinding.Student" />
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{stu.name}"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{stu.addr}"/>
    </LinearLayout>
</layout>

可以看到我們的xml佈局和以前還有有一定的差別的,但是差別也不是很大。 
最後來看看Activity怎麼寫。
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setStu(new Student("loader", "山東萊蕪"));
    }
}

Activity的程式碼非常簡單,就添加了兩行程式碼,而且,值得注意的是:我們並沒有findViewById然後再去setText。 
這段小程式碼執行的結果大家可能已經猜到了,就是在介面上顯示loader山東萊蕪兩句話。

)

在看完小例項後,大家是不是感覺棒棒噠? 沒有了之前的find控制元件,沒有了setText,Activity程式碼更加簡潔明瞭! 
下面開始,我們進入Data Binding的學習!

三、 初始Data Binding 
上面的程式碼算是帶領我們進入了Data Binding的世界,那我們先從佈局檔案開始入手Data Binding吧。再來看看上面的佈局檔案。

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="stu"
            type="org.loader.androiddatabinding.Student" />
    </data>
    ...
</layout>

我們的根節點變成了layout,在layout的子節點中分成兩部分,第一部分是data節點,第二部分才是我們之前的根節點,在data節點下我們又定義了一個variable, 
從名稱上看,這應該是一個變數,變數的名稱是stu,型別是org.loader.androiddatabinding.Student,這類似我們在java檔案中這麼定義:
 org.loader.androiddatabinding.Student stu;
ok,這樣很好理解了吧,不過這裡要寫Student完整的包名,一個還好,如果這裡我們需要多個Student呢?要累死? NO,NO,NO,我們還可以向寫java檔案那樣匯入包。
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="org.loader.app2.Student" />
        <variable
            name="stu"
            type="Student" />
    </data>
    ...
</layout>

這樣寫,就類似於java的

import org.loader.app2.Student;...Student stu;...

既然變數我們定義好了,那該怎麼使用呢?還是看上面的xml檔案。

<layout xmlns:android="http://schemas.android.com/apk/res/android">
  ...
  <LinearLayout
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="wrap_content">
      <TextView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{stu.name}"/>

      <TextView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{stu.addr}"/>
  </LinearLayout>
</layout>

恩,注意看兩個TextViewandroid:text,它的值是一個以@開始,以{}包裹的形式出現,而內容呢?是stu.name。stu就是我們上面定義的variable
name還記得嗎?是我們Student類中的一個變數。其實這裡就會去呼叫stu.getName()方法。 
好了,很快,我們就入門了Data Binding,下面讓我們來多定義幾個變數試試看。
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="org.loader.app2.Student" />
        <variable
            name="stu"
            type="Student" />
        <variable
            name="str"
            type="String"/>
        <variable
            name="error"
            type="boolean"/>
        <variable
            name="num"
            type="int" />
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{stu.name}"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{str}"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(num)}"/>
    </LinearLayout>
</layout>

來看看定義的變數,多了好幾個,有一個String型別的變數我們並沒有導包,這裡說明一下,和在java裡一樣,java.lang包裡的類,我們是可以不用導包的,再往下,一個booleanint型別的變數,都是java基本型別的,所以說嘛,在這裡定義變數,你就想成是在java裡定義就ok。 
再來看看這幾個TextView,第二個,我們直接使用@{str}來為android:text設定成上面定義個str的值,繼續往下要注意了,我們使用了

android:text="@{String.valueOf(num)}"

來設定了一個int型別的變數,大家都知道我們在給android:text設定int型別的值時一定要轉化為String型別,要不它就認為是資原始檔了,這裡我們還學到了一點,在xml中,我們不僅可以使用變數,而且還可以呼叫方法!

四、 變數定義的高階部分 
在上面,我們學會了如何去在xml中定義變數,但是不知道你發現沒?我們沒有定義像ListMap等這樣的集合變數。那到底能不能定義呢?答案肯定是可以的,而且定義的方式和我們上面的基本一致,區別就在於我們還需要為它定義key的變數,例如:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="org.loader.app2.Student" />
        <import type="android.graphics.Bitmap" />
        <import type="java.util.ArrayList" />
        <import type="java.util.HashMap" />
        <variable
            name="stu"
            type="Student" />
        <variable
            name="str"
            type="String"/>
        <variable
            name="error"
            type="boolean"/>
        <variable
            name="num"
            type="int" />
        <variable
            name="list"
            type="ArrayList<String>" />
        <variable
            name="map"
            type="HashMap<String, String>" />
        <variable
            name="array"
            type="String[]" />

        <variable
            name="listKey"
            type="int" />
        <variable
            name="mapKey"
            type="String" />
        <variable
            name="arrayKey"
            type="int" />
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{stu.name}"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{str}"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(num)}"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{list[listKey]}"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{map[`name`]}"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{array[0]}"/>
    </LinearLayout>
</layout>

這段程式碼比較長,但是我們僅關心那幾個集合和陣列,可以看到我們定義集合和定義普通變數一樣,只不過這裡我們還指定了一些的泛型,例如:ArrayList&lt;String>。 
下面我們還為下面使用這些集合準備了幾個key,也都是變數。 
繼續看看怎麼使用,和我們在java中使用不同,這裡都是以:集合變數名[key]的形式使用,如果你的key是一個字面字串可以使用反引號,也可以使用轉義後的雙引號。恩,這裡也沒有什麼可以說的了,大家多看幾遍就掌握了,都是概念性的東西,記住就ok。

五、在java程式碼中使用 
前面定義了這麼多變數,但是我們還沒有給他們賦值!在哪賦值呢?肯定是在java程式碼中使用了,大部分情況我們還是在Activity中去使用它,以前我們都是在onCreate方法中通過setContentView去設定佈局,但現在不一樣了,現在我們是用過DataBindingUtil類的一個靜態方法setContentView設定佈局,同時該方法會返回一個物件,什麼物件?這個物件有點特殊,它是一個自動生成的類的物件,看下面:

@Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       ActivityMainBinding binding = DataBindingUtil.setContentView(this,
               R.layout.activity_main);
    }

看到ActivityMainBinding了嗎?就是它!那自動生成有什麼規則了沒?當然有了,記好了:

將我們佈局檔案的首字母大寫,並且去掉下劃線,將下劃線後面的字母大寫,加上Binding組成。

看看上面的類,是不是符合這個規則。繼續看看這個物件哪來的,是通過

DataBindingUtil.setContentView(this, R.layout.activity_main);

返回的,DataBindingUtil.setContentView的兩個引數分別是當前Activity和佈局檔案。那接下來,就是我們關心的給變數賦值了。
@Override
protected void onCreate(Bundle savedInstanceState) {
   ...
    binding.setStu(new Student("loader"));
    binding.setStr("string");
    binding.setError(false);

    ArrayList<String> list = new ArrayList<String>() {
        {
            add("arraylist");
        }
    };
    binding.setList(list);
    binding.setListKey(0);

    HashMap<String, String> map = new HashMap<String, String>() {
        {
            put("name", "hashmap");
        }
    };
    binding.setMap(map);
//        binding.setMapKey("name");

    String[] array = new String[1];
    array[0] = "array";
    binding.setArray(array);
    binding.setArrayKey(0);
}

一連串的binding.setXXX,這個XXX是什麼呢?就是我們在xml中定義的那些變數首字母大寫了!也沒好好說的吧,多看幾遍。

六、 表示式 
短暫的幸福時光,我們還是要告別java程式碼了,繼續回到xml中,這一塊,我們來學習一下表達式,什麼?這玩意在xml中還支援表示式!

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text='@{error ? "error" : "ok"}'/>

還記得上面我們定義了一個boolean的變數沒有用到,這裡我們就用到了,看好android:text,這裡是一個三元表示式,如果error是true,則text就是error,否則是ok。這裡還支援null合併操作,什麼是null合併,相信看一眼你就知道了
android:text='@{str==null ?? "not null"}'

簡單解釋一下,如果str是null,text的值就是str本身,否則就是”not null”。 
它還支援一下表達式:

  • Mathematical + - / * %
  • String concatenation +
  • Logical && ||
  • Binary & | ^
  • Unary + - ! ~
  • Shift >> >>> <<
  • Comparison == > < >= <=
  • instanceof
  • Grouping ()
  • Literals - character, String, numeric, null
  • Cast
  • Method calls
  • Field access
  • Array access []
  • Ternary operator ?:

但是它不支援一下表達式:

  • this
  • super
  • new
  • Explicit generic invocation

七、 其他遺漏點 
說到這裡,xml中的事情基本算完了,但是還有幾個小地方沒有說,順便說一下。 
1. 設定別名 
假如我們import了兩個相同名稱的類咋辦?別怕,別名來拯救你!例如:

...
<data>
  <import type="xxx.Name" alias="MyName">
  <import type="xxx.xx.Name">
</data>
<TextView xxx:@{MyName.getName()}>
<TextView xxx:@{Name.getName()}>
...

  1. 自定義Binding名稱 
    還記得系統為我們生成好的那個binding類名嗎?如果只能使用那樣的是不是有點太暴力了?好在google對我們還算友好了,允許我們自定義binding名稱,定製名稱也很簡單,就是給data一個class欄位就ok。 
    例如:
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box; font-family: 'Source Code Pro', monospace; font-size: 14px; line-height: 20px; white-space: pre; background-color: rgba(128, 128, 128, 0.0470588);"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">data</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">class</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">".Custom"</span>></span><span style="color: rgb(51, 51, 51); font-family: 'Source Code Pro', monospace; font-size: 14px; line-height: 20px; white-space: pre; background-color: rgba(128, 128, 128, 0.0470588);">...</span><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box; font-family: 'Source Code Pro', monospace; font-size: 14px; line-height: 20px; white-space: pre; background-color: rgba(128, 128, 128, 0.0470588);"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">data</span>></span>

那麼:DataBindingUtils.setContentView返回的binding類就是:你的應用包名.Custom

八、事件繫結 
大家都知道,在xml中我們可以給button設定一個onClick來達到事件的繫結,現在DataBinding也提供了事件繫結,而且不僅僅是button。 
來看一下:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="org.loader.app3.EventHandlers" />
        <variable
            name="handlers"
            type="EventHandlers" />
    </data>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="CLICK ME"
            android:onClick="@{handlers.handleClick}"/>
    </LinearLayout>
</layout>

定義了一個EventHandlers型別的handlers變數,並在onClick的時候執行EventHandlershandleClick方法。 
繼續看看EventHandlers是怎麼寫的。
public class EventHandlers {
    public void handleClick(View view) {
        Toast.makeText(view.getContext(), "you clicked the view", Toast.LENGTH_LONG).show();
    }
}

很簡單,就是簡單的Toast了一下,這裡要注意的是,handlerClick方法需要一個View的引數。

九、 資料物件 
我們學會了通過binding為我們的變數設定資料,但是不知道你有沒有發現一個問題,當我們資料改變的時候會怎樣?資料是跟隨著改變呢?還是原來的資料呢?這裡告訴你答案:很不幸,顯示的還是原來的資料?那有沒有辦法讓資料來源發生變化後顯示的資料也隨之發生變化?先來想想ListView是怎麼做的, ListView的資料是通過Adapter提供的,當資料發生改變時,我們通過notifyDatasetChanged通過UI去改變資料,這裡面的原理其實就是內容觀察者,慶幸的是DataBinding也支援內容觀察者,而且使用起來也相當方便!

BaseObservable 
我們可以通過Observable的方式去通知UI資料已經改變了,當然了,官方為我們提供了更加簡便的方式BaseObservable,我們的實體類只需要繼承該類,稍做幾個操作,就能輕鬆實現資料變化的通知。如何使用呢? 首先我們的實體類要繼承BaseObservale類,第二步在Getter上使用註解@Bindable,第三步,在Setter裡呼叫方法notifyPropertyChanged,第四步,完成。就是這麼簡單,下面我們來實際操作一下。 
首先定義一個實體類,並繼承BaseObservable

public class Student extends BaseObservable {
    private String name;

    public Student() {
    }

    public Student(String name) {
        this.name = name;
    }

    @Bindable
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(org.loader.app4.BR.name);
    }
}

觀察getName方法,我們使用了@Bindable註解,觀察setName,我們呼叫了notifyPropertyChanged方法,這個方法還需要一個引數,這裡引數類似於R.java,儲存了我們所有變數的引用地址,這裡我們使用了name。 
再來看看佈局檔案。
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data class=".Custom">
        <import type="org.loader.app4.Student" />
        <variable
            name="stu"
            type="Student"/>
        <variable
            name="click"
            type="org.loader.app4.MainActivity" />
    </data>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="@{click.click}"
        android:text="@{stu.name}"/>
</layout>

不多說了,我們給TextView設定了文字,還有點選事件。Activity,
public class MainActivity extends AppCompatActivity {

    private Student mStu;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        org.loader.app4.Custom binding = DataBindingUtil.setContentView(this,
                R.layout.activity_main);
        mStu = new Student("loader");
        binding.setStu(mStu);
        binding.setClick(this);
    }

    public void click(View view) {
        mStu.setName("qibin");
    }
}

這段程式碼,首先顯示的是loader,當我們點選TextView時,介面換成qibin。

ObservableFields家族 
上面使用BaseObservable已經非常容易了,但是google工程師還不滿足,繼續給我們封裝了一系列的ObservableFields,這裡有ObservableFieldObservableBoolean,ObservableByte,ObservableChar,ObservableShort,ObservableInt,ObservableLong,ObservableFloat,ObservableDouble,ObservableParcelable
ObservableFields的使用方法就更加簡單了,例如下面程式碼,

public class People {
    public ObservableField<String> name = new ObservableField<>();
    public ObservableInt age = new ObservableInt();
    public ObservableBoolean isMan = new ObservableBoolean();
}

很簡單,只有三個ObservableField變數,並且沒有getter和setter,因為我們不需要getter和setter。 
在xml中怎麼使用呢?
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data class=".Custom">

        <variable
            name="people"
            type="org.loader.app4.People" />
    </data>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{people.name}"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(people.age)}"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text='@{people.isMan ? "man" : "women"}'/>
    </LinearLayout>
</layout>

也很簡單,直接使用變數,那怎麼賦值和取值呢?這些ObservableField都會有一對getset方法,所以使用起來也很方便了:
...
mPeople = new People();
binding.setPeople(mPeople);
mPeople.name.set("people");
mPeople.age.set(19);
mPeople.isMan.set(true);
...

也不多說了。

Observable Collections 
既然普通的變數我們有了ObservableFields的分裝,那集合呢?當然也有啦,來看著兩個:ObservableArrayMap,ObservableArrayList。使用和普通的Map、List基本相同,直接看程式碼:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data class=".Custom">
        <variable
            name="map"
            type="android.databinding.ObservableArrayMap<String,String>" />
        <variable
            name="list"
            type="android.databinding.ObservableArrayList<String>" />
    </data>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{map[`name`]}"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{list[0]}"/>
    </LinearLayout>
</layout>

在佈局中,使用方式和普通的集合一樣,如果看不太懂,可以往上翻部落格,看上面的集合是怎麼使用的。 
在來看java檔案,怎麼設定資料,
ObservableArrayMap<String, String> map = new ObservableArrayMap<>();
ObservableArrayList<String> list = new ObservableArrayList<>();
map.put("name", "loader or qibin");
list.add("loader!!!");
binding.setMap(map);
binding.setList(list);

太簡單了,簡直和ListMap使用方法一模一樣!!! 

十、inflate 
不知道大家注意沒有,上面的程式碼我們都是在activity中通過DataBindingUtil.setContentView來載入的佈局的,現在有個問題了,如果我們是在Fragment中使用呢?Fragment沒有setContentView怎麼辦?不要著急,Data Binding也提供了inflate的支援! 
使用方法如下,大家肯定會覺得非常眼熟。

MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater);
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false);

接下來,我們就嘗試著在Fragment中使用一下Data Binding吧。 
首先還是那個學生類,Student
public class Student extends BaseObservable {
    private String name;
    private int age;

    public Student() {
    }

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

    @Bindable
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        notifyPropertyChanged(org.loader.app5.BR.age);
    }

    @Bindable
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(org.loader.app5.BR.name);
    }
}

繼續,activity的佈局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>

activity的程式碼,
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, new MyFragment()).commit();
    }
}
重點來了,我們這裡data binding的操作都放在了fragment裡,那麼我們先來看看fragment的佈局。
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data class=".Custom">
        <import type="org.loader.app5.Student" />
        <variable
            name="stu"
            type="Student" />
        <variable
            name="frag"
            type="org.loader.app5.MyFragment" />
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{frag.click}"
            android:text="@{stu.name}"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(stu.age)}"/>
    </LinearLayout>
</layout>
兩個TextView分別綁定了Student的name和age欄位,而且給name添加了一個點選事件,點選後會呼叫Fragment的click方法。我們來迫不及待的看一下Fragment怎麼寫:
public class MyFragment extends Fragment {

    private Student mStu;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        org.loader.app5.Custom binding = DataBindingUtil.inflate(inflater,
                R.layout.frag_layout, container, false);
        mStu = new Student(20, "loader");
        binding.setStu(mStu);
        binding.setFrag(this);
        return binding.getRoot();
    }

    public void click(View view) {
        mStu.setName("qibin");
        mStu.setAge(18);
    }
}

onCreateView中,不同於在Activity中,這裡我們使用了DataBindingUtil.inflate方法,接受4個引數,第一個引數是一個LayoutInflater物件,正好,我們這裡可以使用onCreateView的第一個引數,第二個引數是我們的佈局檔案,第三個引數是一個ViewGroup,第四個引數是一個boolean型別的,和在LayoutInflater.inflate一樣,後兩個引數決定了是否想container中新增我們載入進來的佈局。 
下面的程式碼和我們之前寫的並無差別,但是有一點,onCreateView方法需要返回一個View物件,我們從哪獲取呢?ViewDataBinding有一個方法getRoot可以獲取我們載入的佈局,是不是很簡單? 
來看一下效果:

十一、 Data Binding VS RecyclerView 
有了上面的思路,大家是不是也會在ListView和RecyclerView中使用了?我們僅以一個RecyclerView來學習一下。 
首先來看看item的佈局,

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="stu"
            type="org.loader.app6.Student" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{stu.name}"
            android:layout_alignParentLeft="true"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(stu.age)}"
            android:layout_alignParentRight="true"/>

    </RelativeLayout>
</layout>

可以看到,還是用了那個Student實體,這樣得程式碼,相信你也已經看煩了吧。 
那我們來看看activity的。
private RecyclerView mRecyclerView;
private ArrayList<Student> mData = new ArrayList<Student>() {
    {
        for (int i=0;i<10;i++) add(new Student("loader" + i, 18 + i));
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mRecyclerView = (RecyclerView) findViewById(R.id.recycler);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this,
            LinearLayoutManager.VERTICAL, false));
    mRecyclerView.setAdapter(new MyAdapter(mData));
}

這裡給RecyclerView設定了一個Adapter,相信最主要的程式碼就在這個Adapter裡。
private class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private ArrayList<Student> mData = new ArrayList<>();

    private MyAdapter(ArrayList<Student> data) {
        mData.addAll(data);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater
                .from(viewGroup.getContext()), R.layout.item, viewGroup, false);
        ViewHolder holder = new ViewHolder(binding.getRoot());
        holder.setBinding(binding);
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        viewHolder.getBinding().setVariable(org.loader.app6.BR.stu, mData.get(i));
        viewHolder.getBinding().executePendingBindings();
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }

    class ViewHolder extends RecyclerVie