Google官方黑科技
為什麼?
之前開發,一直使用依賴注入框架 - ButterKnife。自從Android Studio升級3.0以來,ButterKnife一直受到Gradle API的影響,不能升級Gradle版本,這也算是一大詬病,導致於升級Android studio時,慎之又慎。偶爾想到還有Google的官方框架 - DataBinding,我想是入手的時候了…本文是官方文件的翻譯,只是簡明的介紹瞭如何使用Data Binding。
概述
這篇文章介紹瞭如何使用Data Binding庫來寫宣告的layouts檔案,並且用最少的程式碼來繫結你的app邏輯和layouts檔案。
Data Binding庫不僅靈活而且廣泛相容- 它是一個support庫,因此你可以在所有的Android平臺最低能到Android 2.1(API等級7+)上使用它。
要使用資料繫結,Android Plugin for Gradle 1.5.0-alpha1
或更高版本是必需的。 瞭解如何更新Android Plugin for Gradle
。
構建環境
要開始使用資料繫結,需用在Android SDK管理器的Support repository
中下載支援庫。
要配置應用程式可以使用資料繫結,將dataBinding
元素新增到build.gradle
檔案中的app模組中。
使用以下程式碼片段配置資料繫結:
android {
....
}
dependencies {
annotationProcessor 'com.android.databinding:compiler:3.1.2'
}
如果app
模組依賴於使用資料繫結的庫,則app
模組也必須在其build.gradle檔案中配置資料繫結。
同時,確保使用的Android Studio版本相容資料繫結功能。Android Studio1.3
以及更高版本支援資料繫結,如[Android Studio支援資料繫結]中所述。
資料繫結編譯器V2
Android Gradle Plugin 3.1.0 Canary 6
附帶一個可選的新編譯器。 要開始使用它,更新gradle.properties
檔案以包含以下行:
android.databinding.enableV2=true
在編譯器v2中:
ViewBinding
Android Gradle Plugin
生成的。 如果java編譯由於一個不相關的原因而失敗,這避免了導致得到太多誤報錯誤。- 在
V1
中 ,binding
系列的類將會在app編譯完成後再次生成(去分享生成的程式碼並關聯到 常量BR
和R
檔案)。在V2
中,繫結庫將儲存其生成的繫結類以及對映資訊,這些資訊可顯著提高多模組專案的資料繫結效能。
注意: 新的V2編譯器是向後不相容,所以使用v1編譯的庫不能被V2使用,反之亦然。
V2
還刪除了一些很少使用的功能以允許這些更改:
- 在
V1
中,應用程式能夠提供可以覆蓋依賴項中的介面卡的繫結介面卡。在V2
中,它只會對自己的模組/應用程式及其依賴項中的程式碼生效。 - 以前,如果一個佈局檔案在2個或更多不同資源配置中包含具有相同標識但不同型別的View,則資料繫結會查詢最常見的父類。在V2中,當配置之間的型別不匹配時,它始終預設為
View
。 - 在
V2
中,不同的模組不能在manifest
中使用相同的包名稱,因為資料繫結將使用該包名稱來生成繫結對映類。
資料繫結佈局檔案
資料繫結表示式
資料繫結佈局檔案略有不同,以layout
作為根標籤,緊隨跟著data
元素和view
根節點。這個view
根節點是在非繫結佈局檔案中的根標籤。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<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}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"/>
</LinearLayout>
</layout>
在data內描述了一個名為user的variable
,使其可以在這個layout中使用:
<variable name="user" type="com.example.User"/>
佈局中的表示式使用@{}
語法將variable
的屬性寫入View
的屬性中,下面是一個TextView
的text
設定為user
的firstName
屬性:
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
資料物件
現在假設有一個普通的Java物件(POJO)User:
public class User {
public final String firstName;
public final String lastName;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
這種型別的物件具有永不改變的資料。在應用程式中通常會讀取一次資料,之後永遠不會更改。 也可以使用JavaBeans物件:
public class User {
private final String firstName;
private final String lastName;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return this.firstName;
}
public String getLastName() {
return this.lastName;
}
}
從資料繫結的角度來看,這兩個類是等價的。用於TextView
的android:text
屬性的表示式@{user.firstName}
將訪問前一類中的firstName
欄位和後一類中的getFirstName()
方法。或者,如果該方法存在,它也將被解析為firstName()
。
繫結資料
預設情況下,將根據佈局檔案的名稱生成一個Binding
類,並將其轉換為Pascal
格式併為其新增字尾Binding
。比如,上面的佈局檔案是main_activity.xml
,所以生成的類是MainActivityBinding
。這個類將佈局屬性(例如,user
變數)的所有繫結儲存到佈局的Views中,並知道如何為繫結表示式分配值。建立繫結的最簡單方法是在inflate
時執行此操作:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
User user = new User("Test", "User");
binding.setUser(user);
}
你完成了! 執行該應用程式,將在使用者介面中看到測試User
。或者,可以通過以下方式獲取檢視:
MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());
如果在ListView或RecyclerView介面卡內使用資料繫結,推薦這麼使用:
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
//or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
事件處理
資料繫結允許編寫表示式來處理從View
中分派的事件(例如onClick)。除少數例外,事件屬性名稱由監聽方法的名稱管理。例如,View.OnLongClickListener
有一個onLongClick()
方法,所以這個事件的屬性是android:onLongClick
。
處理事件有兩種方式:
- 方法引用:在表示式中,可以引用符合偵聽方法簽名的方法。當表示式求值為方法引用時,資料繫結將方法引用和持有者物件封裝在偵聽中,並將該監聽繫結到在目標View上。如果表示式求值為null,則資料繫結不會建立監聽,而是將監聽設定為null。
- 監聽繫結:這些是在事件發生時被執行的lambda表示式。資料繫結總是建立一個設定在View上的監聽。 當事件分派時,監聽執行lambda表示式。
方法引用
事件可以直接繫結到處理方法,類似於將android:onClick
分配給Activity中的方法。與View:onClick
屬性相比,一個主要優勢是表示式在編譯時處理,所以如果該方法不存在或其簽名不正確,則會收到編譯時錯誤。
方法引用和監聽繫結之間的主要區別在於實際的監聽實現是在資料繫結時建立的,而不是在觸發事件時建立的。如果希望在事件發生時對錶達式求值,則應該使用偵聽繫結。
要將事件分配給其處理方法,使用正常的繫結表示式,其值是要呼叫的方法名稱。 例如,如果你的資料物件有兩種方法:
public class MyHandlers {
public void onClickFriend(View 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>
注意,表示式中方法的簽名必須與Listener物件中方法的簽名完全匹配.
對於被引用的方法,其引數必須包含一個引數(view: View).
監聽繫結
監聽繫結是事件發生時執行繫結表示式。它與方法引用類似,但它執行任意資料繫結表示式。 此功能適用於Gradle 2.0及更高版本的Android Gradle Plugin
.
在方法引用中,方法的引數必須與監聽事件的引數匹配。在監聽繫結中,只要返回值必須與偵聽的期望返回值相匹配(除非預期返回值為void)。例如,您可以擁有一個具有以下方法的presenter
類:
public class Presenter {
public void onSaveClick(Task task){}
}
然後,您可以將click事件繫結到Presenter上
,如下所示:
<?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>
監聽由僅允許作為表示式根元素的lambda表示式表示。當在表示式中使用回撥時,資料繫結會自動為該事件建立必要的偵聽和註冊。當View觸發事件時,資料繫結將求值給定的表示式。 與常規繫結表示式一樣,在求值這些偵聽表示式時,仍然可以獲得資料繫結的空值和執行緒安全。
注意,在上面的例子中,我們沒有定義view
作為傳入onClick(android.view.View)
的引數。監聽繫結為監聽引數提供了兩種選擇:可以忽略該方法的所有引數或命名所有引數.如果更喜歡命名引數,則可以在表示式中使用它們。例如,上面的表示式可以寫成:
android:onClick="@{(view) -> presenter.onSaveClick(task)}"
或者如果想在表示式中使用引數,可以這麼做:
public class Presenter {
public void onSaveClick(View view, Task task){}
}
android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"
可以使用帶有多個引數的lambda表示式:
public class Presenter {
public void onCompletedChanged(Task task, boolean completed){}
}
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />
如果正在監聽的事件返回的值不是void
,則表示式必須返回相同型別的值。例如,如果想要監聽長按事件,則表示式應返回boolean
。
public class Presenter {
public boolean onLongClick(View view, Task task){}
}
android:onLongClick="@{(theView) -> presenter.onLongClick(theView, task)}"
如果由於空物件而無法求值表示式,Data Binding
將返回該型別的預設Java值。 例如,參考型別為null,int為0,boolean為false等。
如果需要使用帶斷言的表示式(例如三元),則可以使用void作為一個表示式:
android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"
避免複雜監聽
監聽表示式非常強大,可以讓程式碼非常容易閱讀。另一方面,監聽包含複雜表示式會使佈局難以閱讀和無法維護。這些表示式應該像從UI中傳遞可用資料到回撥方法一樣簡單。應該在監聽表示式呼叫的回撥方法內實現所有業務邏輯。
存在一些專用的單擊事件處理,它們需要除android:onClick
之外的其他屬性,以避免衝突. 已建立以下屬性以避免此類衝突:
類 | 監聽設定 | 屬性 |
---|---|---|
SearchView | setOnSearchClickListener(View.OnClickListener) | android:onSearchClick |
ZoomControls | setOnZoomInClickListener(View.OnClickListener) | android:onZoomIn |
ZoomControls | setOnZoomOutClickListener(View.OnClickListener) | android:onZoomOut |
佈局詳情
import
data
元素內可以使用零個或多個import
元素。 這些可以輕鬆地在佈局檔案中的引用類,就像在Java中一樣。
<data>
<import type="android.view.View"/>
</data>
現在,可以在繫結表示式中使用View
:
<TextView
android:text="@{user.lastName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
當有類名衝突時,其中一個類可能會使用alias
重新命名:
<import type="android.view.View"/>
<import type="com.example.real.estate.View"
alias="Vista"/>
現在,Vista
可以被用來引用com.example.real.estate.View
並且View
可以用來在佈局檔案中引用android.view.View
。 匯入的型別可以用作variable
和表示式中的型別引用:
<data>
<import type="com.example.User"/>
<import type="java.util.List"/>
<variable name="user" type="User"/>
<variable name="userList" type="List<User>"/>
</data>
注意:Android Studio尚未支援
import
,因此匯入變數的自動補全功能可能無法在IDE中使用。但,應用程式仍然可以正常編譯,可以通過在變數定義中使用完全限定名稱來解決這個IDE問題。
<TextView
android:text="@{((User)(user.connection)).lastName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
在表示式中引用靜態欄位和方法時,也可以使用匯入的型別:
<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"/>
就像在Java中一樣,java.lang。*
是自動匯入的。
variable
data
元素內可以使用任意數量的variable
元素。每個variable
元素描述了可以在佈局上設定的屬性,以用於佈局檔案中的繫結表示式。
<data>
<import type="android.graphics.drawable.Drawable"/>
<variable name="user" type="com.example.User"/>
<variable name="image" type="Drawable"/>
<variable name="note" type="String"/>
</data>
variable
型別在編譯時被檢查,所以如果一個variable
實現了android.databinding.Observable
或者是一個可觀察的集合,那麼它應該被對映在型別中。 如果variable
不是實現Observable *
介面的基類或介面,將不會觀察變數的變化!
當各種配置(例如橫向或縱向)有不同的佈局檔案時,variable
將被合併。 這些佈局檔案之間不得存在衝突的variable
定義。
生成的繫結類將為每個描述的變數建立一個setter
和getter
方法。 變數將採用Java
的預設值,直到呼叫setter
為止 - 引用型別為null,int為0,boolean為false。
在生成繫結類時,根據需要將預設建立一個用於繫結表示式的特殊變數context
。context
的值是根View呼叫getContext()
獲取的Context
,也就是根View的Context
。如果顯示的宣告一個名為context
變數,將會覆蓋其值。
自定義繫結類名稱
預設情況下,根據佈局檔案的名稱生成一個Binding
類,以大寫字母開頭,刪除下劃線(_)並大寫其後的字母,然後新增字尾Binding
。該類將放置在模組包下的databinding
包中。例如,佈局檔案contact_item.xml
將生成類ContactItemBinding
。如果模組包是com.example.my.app
,那麼它將被放置在com.example.my.app.databinding
中。
通過調整data
元素的class
屬性,繫結類可以重新命名或放置在不同的包中。 例如:
<data class="ContactItem">
...
</data
這會在模組包中的databinding
包中生成名為ContactItem
的繫結類。如果生成的類在模組包中的其他包中,則它可能會以。
作為字首:
<data class=".ContactItem">
...
</data>
這樣,生成的類ContactItem
將在模組包中。如果提供完整的包名,則可以使用任意的包:
<data class="com.example.ContactItem">
...
</data>
include
通過在include
屬性中使用應用程式名稱空間(即bind
)和變數名稱,變數可以從父佈局傳遞到include
佈局的繫結中:
<?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>
在這裡,name.xml
和contact.xml
佈局檔案中都必須有一個變數user
。
資料繫結不支援inclucde
作為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>
<include layout="@layout/name"
bind:user="@{user}"/>
<include layout="@layout/contact"
bind:user="@{user}"/>
</merge>
</layout>
表示式語言
共同特性
表示式語言看起來很像Java表示式。如下這些都是相同的:
- 數學運算子
+ - / *%
- 字串連線
+
- 邏輯運算子
&& ||
- 二進位制運算子
&|^
- 一元運算子
+ - !〜
- 位移運算子
>> >>> <<
- 比較運算子
==> <> = <=
instanceof
Grouping()
- 字面值 - character, String, numeric, null
- 求值
- 方法呼叫
- 欄位訪問
- 陣列訪問
[]
- 三元操作符
?:
例如:
android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'
缺失的操作符
可以在Java
中使用但在表示式語法中缺失的操作符:
- this
- super
- new
- 顯式泛型呼叫
null合併運算子(??
)
如果null合併運算子(??
)的左運算元不為空,則選擇左運算元,否則選擇右運算元。
選擇左運算元(如果它不為空)或選擇右(如果它為空)。
android:text="@{user.displayName ?? user.lastName}"
等價於:
android:text="@{user.displayName != null ? user.displayName : user.lastName}"
屬性引用
在前面,資料繫結表示式中已經討論了:簡短形式的JavaBean引用
。 當表示式引用某個類的屬性時,它將對欄位,getter
和ObservableFields
使用相同的引用格式。
android:text="@{user.lastName}"
避免NullPointerException
生成的資料繫結程式碼會自動檢查null
並避免空指標異常(NullPointerException
)。 例如,在表示式@{user.name}
中,如果user
為空,那麼user.name
將預設為null
。如果引用了user.age
,而age
是一個int
型別,那麼它將預設為0。
集合
常見的集合,比如array, lists sparse list, and map,可以使操作符[]
訪問:
<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>"/>
<variable name="index" type="int"/>
<variable name="key" type="String"/>
</data>
…
android:text="@{list[index]}"
…
android:text="@{sparse[index]}"
…
android:text="@{map[key]}"
字串字面值
如下,可以使用單引號在屬性值上,用雙引號在字串字面值上:
android:text='@{map["firstName"]}'
也可以反過來使用:
android:text="@{map[`firstName`}"
android:text="@{map['firstName']}"
資源
可以將使用正常語法的資源訪問語句作為表示式的一部分:
android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
可以為格式化string
和plurals
提供引數:
android:text="@{@string/nameFormat(firstName, lastName)}"
android:text="@{@plurals/banana(bananaCount)}"
當一個plurals
有多個引數時,所有引數都應該傳遞:
Have an orange
Have %d oranges
android:text="@{@plurals/orange(orangeCount, orangeCount)}"
一些資源需要顯式型別引用:
型別 | 正常引用 | 表示式引用 |
---|---|---|
String[] | @array | @stringArray |
int[] | @array | @intArray |
TypedArray | @array | @typedArray |
Animator | @animator | @animator |
StateListAnimator | @animator | @stateListAnimator |
color int | @color | @color |
ColorStateList | @color | @colorStateList |
資料物件
任何普通的POJO
都可用於資料繫結,但修改POJO不會通知UI更新。資料繫結的真正的強大特性是在POJO更改時通知UI更新。在資料繫結中,有三種不同的資料更改通知機制:可觀察物件,可觀察欄位和可觀察集合。
當這些可觀察資料物件之一繫結到UI並且資料物件的屬性更改時,UI將自動更新。
可觀察物件
實現android.databinding.Observable
介面的類將允許繫結將單個監聽新增到繫結物件以監聽該物件上所有屬性的更改。
android.databinding.Observable
介面具有新增和刪除監聽的機制,但通知由開發人員決定。為了簡化開發,建立了基類android.databinding.BaseObservable
,以實現監聽註冊機制。實現介面的資料類仍然負責在屬性更改時分發通知。這是通過使用android.databinding.Bindable
註解getter
並在setter
中分發通知。
private static class User extends BaseObservable {
private String firstName;
private String lastName;
@Bindable
public String getFirstName() {
return this.firstName;
}
@Bindable
public String getLastName() {
return this.lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
}
public void setLastName(String lastName) {
this.lastName = lastName;
notifyPropertyChanged(BR.lastName);
}
}
android.databinding.Bindable
註解在編譯時在BR類檔案中生成一個列表。BR類檔案將在模組包中生成。如果無法更改資料類的基類,則可以使用方便的android.databinding.PropertyChangeRegistry
實現android.databinding.Observable
介面,以有效地儲存和通知監聽。
可觀察欄位
建立android.databinding.Observable
類會耗費一定時間,所以想要節省時間或具有少量可觀察的屬性,開發人員可能會使用android.databinding.ObservableField
及其同級的android.databinding.ObservableBoolean
,android.databinding.ObservableByte
,android.databinding.ObservableChar
,android.databinding.ObservableShort
,android.databinding.ObservableInt
,android.databinding.ObservableLong
,android.databinding.ObservableFloat
,android.databinding.ObservableDouble
和android.databinding.ObservableParcelable
。可觀察欄位是一個具有單個欄位的獨立的可觀察物件。基本資料型別在訪問操作期間避免裝箱和拆箱。如果要使用可觀察欄位,需要在資料類中建立public final
欄位:
private static class User {
public final ObservableField<String> firstName =
new ObservableField<>();
public final ObservableField<String> lastName =
new ObservableField<>();
public final ObservableInt age = new ObservableInt();
}
要訪問該值,需要使用set
和get
方法:
user.firstName.set("Google");
int age = user.age.get();
可觀察集合
一些應用程式使用很多動態結構來儲存資料。可觀察集合允許對這些資料物件通過鍵值訪問。當鍵是引用型別(如String
)時,android.databinding.ObservableArrayMap
非常有用。
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.put("age", 17);
在佈局中,可以通過String
型別的鍵值訪問map
:
<data>
<import type="android.databinding.ObservableMap"/>
<variable name="user" type="ObservableMap<String, Object>"/>
</data>
…
<TextView
android:text='@{user["lastName"]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text='@{String.valueOf(1 + (Integer)user["age"])}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
當鍵是一個整數時,android.databinding.ObservableArrayList
是有用的:
ObservableArrayList<Object> user = new ObservableArrayList<>();
user.add("Google");
user.add("Inc.");
user.add(17);
在佈局中,list
可以通過索引訪問:
<data>
<import type="android.databinding.ObservableList"/>
<import type="com.example.my.app.Fields"/>
<variable name="user" type="ObservableList<Object>"/>
</data>
…
<TextView
android:text='@{user[Fields.LAST_NAME]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
建立繫結
生成的繫結類將佈局變數與佈局中的View
連結起來。如前所述,繫結類的名稱和包是可以自定義的。生成的繫結類全部繼承自android.databinding.ViewDataBinding
。
建立
在inflate
以後立即建立繫結,以確保View
層次結構在將帶有表示式的View
繫結到佈局之前不受干擾。有幾種方法可以繫結到佈局。最常見的是使用Binding類中的靜態方法。inflate
方法將inflate
View
層次結構並將其繫結只需一步。有一個更簡單的方式只需要一個LayoutInflater
,另一個則需要一個ViewGroup
:
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater);
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false);
如果佈局使用不同的機制進行inflate
,則可能需要單獨繫結:
MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);
有時繫結不能預先知道。在這種情況下,可以使用android.databinding.DataBindingUtil
類建立繫結:
ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater, layoutId,
parent, attachToParent);
ViewDataBinding binding = DataBindingUtil.bindTo(viewRoot, layoutId);
帶有ID的View
生成Binding類時,將為佈局中的每一個帶有ID
的View
生成一個public final
欄位。該繫結在View層次結構上執行單個傳遞,並使用ID
獲取View
。 這種機制可能比呼叫多個View
的findViewById更快。 例如:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<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:id="@+id/firstName"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"
android:id="@+id/lastName"/>
</LinearLayout>
</layout>
生成的Binding
類將包含:
public final TextView firstName;
public final TextView lastName;
不使用資料繫結的View
,可以沒有id
,但有些view
還是需要在程式碼中來訪問.
Variables
生成的Binding
類,將為每個變數生成相應的get
和set
方法。
<data>
<import type="android.graphics.drawable.Drawable"/>
<variable name="user" type="com.example.User"/>
<variable name="image" type="Drawable"/>
<variable name="note" type