Android官方資料繫結框架DataBinding
轉自:http://blog.csdn.net/qibin0506/article/details/47393725
今天來了解一下android最新給我們帶來的資料繫結框架——Data Binding Library。資料繫結框架給我們帶來了更大的方便性,以前我們可能需要在Activity
裡寫很多的findViewById
,煩人的程式碼也增加了我們程式碼的耦合性,現在我們馬上就可以拋棄那麼多的findViewById
。說到這裡,有人可能會有個疑問:我使用一些註解框架也可以不用findViewById
啊,是的,但是註解註定要拖慢我們程式碼的速度,Data
Binding則不會,官網文件說還會提高解析XML的速度
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>
恩,注意看兩個
TextView
的android: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
包裡的類,我們是可以不用導包的,再往下,一個boolean
和int
型別的變數,都是java基本型別的,所以說嘛,在這裡定義變數,你就想成是在java裡定義就ok。 再來看看這幾個
TextView
,第二個,我們直接使用@{str}
來為android:text
設定成上面定義個str
的值,繼續往下要注意了,我們使用了
android:text="@{String.valueOf(num)}"
來設定了一個int
型別的變數,大家都知道我們在給android:text
設定int
型別的值時一定要轉化為String
型別,要不它就認為是資原始檔了,這裡我們還學到了一點,在xml中,我們不僅可以使用變數,而且還可以呼叫方法!
四、 變數定義的高階部分
在上面,我們學會了如何去在xml中定義變數,但是不知道你發現沒?我們沒有定義像List
、Map
等這樣的集合變數。那到底能不能定義呢?答案肯定是可以的,而且定義的方式和我們上面的基本一致,區別就在於我們還需要為它定義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<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()}>
...
- 自定義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的時候執行EventHandlers
的handleClick
方法。 繼續看看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
,這裡有ObservableField
,ObservableBoolean
,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都會有一對
get
和set
方法,所以使用起來也很方便了:...
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);
太簡單了,簡直和
List
、Map
使用方法一模一樣!!! 十、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