1. 介紹
這篇文章介紹瞭如何使用Data Binding庫來寫聲明的layouts文件,並且用最少的代碼來綁定你的app邏輯和layouts文件。
Data Binding庫不僅靈活而且廣泛兼容- 它是一個support庫,因此你可以在所有的Android平臺最低能到Android 2.1(API等級7+)上使用它。
需要:Android Studio 1.3.0-beta1 或更高版本。
測試版本
請注意:Data Binding庫當前是測試版本。在Data Binding處於測試階段時,開發者應該瞭解以下注意事項:
- 這是旨在生成開發者的反饋功能的測試版本。它可能包含bugs,或者不適合你的使用案例,所以需要您在使用它時自擔風險。即便如此,我們非常希望得到您的反饋!使用 來讓我們知道對於你的使用案例什麼可以工作或者不能工作。
- Data Binding庫的測試版本傾向於顯著的改變,包括那些不是與您的應用程序兼容的源代碼。即,在未來可能會進行大量的返工來更新此庫。
- 雖然伴有標準Android SDK和Google Play服務條款適用警告,開發人員可以隨時發佈內置了與Data Binding庫beta版本的應用程序。而且採用新的庫或工具是一個相當好的主意來徹底測試你的應用程序。
- 我們在這個時候纔剛剛開始與Android Studio的支持。未來會有進一步的Android Studio的支持。
- 通過使用Data Binding庫beta版本,你承認這些警告。
2. 構建環境
要開始使用Data Binding,首先需要在Android SDK Manager的支持庫裏下載該庫。
請確保您使用的是 Android Studio 的兼容版本。Android Studio的Data Binding 插件需要 Android Studio 1.3.0-beta1 或更高版本。
工作環境
你的app要使用Data Binding,需要添加Data Binding到gradle構建文件裏,如下:
dependencies {
classpath "com.android.tools.build:gradle:1.2.3"
classpath "com.android.databinding:dataBinder:1.0-rc0"
}
}
然後確保jcenter在repositories列表裏,如下:
allprojects {
repositories {
jcenter()
}
}
在每一個你想要使用Data Binding的module,添加如下的插件:
apply plugin: ‘com.android.application'
apply plugin: 'com.android.databinding'
Data Binding插件將會在你的項目內添加必需提供的以及編譯配置依賴。
3. Data Binding Layout 文件
Data Binding表達式
Data Binding layout文件有點不同的是:起始根標籤是 layout
,接下來一個 data
元素以及一個 view
的根元素。這個 view
元素就是你沒有使用Data
Binding的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.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的變量屬性,使其可以在這個layout中使用:
<variable name="user" type="com.example.User"/>
在layout的屬性表達式寫作@{}
,下面是一個TextView的text設置爲user的firstName屬性:
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
Data對象
假設你有一個user的plain-old Java Object(POJO):
public class User {
public final String firstName;
public final String lastName;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
這個類型的對象擁有從不改變的數據。在app中它是常見的,可以讀取一次並且之後從不改變。當然也可以使用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;
}
}
從Data Binding的角度來看,這兩個類是等價的。用於TextView中的android:text
屬性的表達式@{user.firstName}
將訪問前者POJO對象中的firstName
和後者JavaBeans對象中的getFirstName()
方法。
Binding數據
默認情況下,一個Binding類會基於layout文件的名稱而產生,將其轉換爲Pascal case(譯註:首字母大寫的命名規範)並且添加“Binding”後綴。上述的layout文件是activity_main.xml
,因此生成的類名是ActivityMainBinding
。此類包含從layout屬性到layout的Views中所有的bindings(例如user
變量),並且它還知道如何給Binding表達式分配數值。創建bindings的最簡單的方式是在inflating(譯註:layout文件與Activity/Fragment的“鏈接”)期間如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
User user = new User("Test", "User");
binding.setUser(user);
}
就是這樣,運行app後,你將會看到Test User。或者你可以通過如下獲取View:
MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());
如果你在ListView或者RecyclerView adapter使用Data Binding時,你可能會使用:
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup,
false);
//or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
4. 深入 Layout 文件
Import
零個或多個import
元素可能在data
元素中使用。這些只用在你的layout文件中添加引用,就像在Java中:
<data>
<import type="android.view.View"/>
</data>
現在,View可以使用你的Binding表達式:
<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"/>
這樣,在該layout文件中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還沒有處理imports,所以自動導入Variable在你的IDE不能使用。您的app仍會正常編譯,你可以在您的Variable定義中使用完全符合規定的名稱來解決該IDE問題。
<TextView
android:text="@{((User)(user.connection)).lastName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
導入的類型還可以在表達式中使用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"/>
就像在Java中,java.lang。*
是自動導入的。
Variables
在data
中可以使用任意數量的variable
元素。每一個variable
元素描述了一個用於layout文件中Binding表達式的屬性。
<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實現了 或 ,這應該反映在類型中。(譯註:需要查找資料來理解)如果variable是一個沒有實現Observable接口的基本類或者接口,Variables不會被observed!
當對於多種配置有不同的layout文件時(如,橫向或縱向),Variables會被合併。這些layout文件之間必須不能有衝突的Variable定義。
產生的Binding類對於每一個描述的Variables都會有setter和getter。這些Variables會使用默認的Java值 - null(引用類型)、0(int)、false(boolean)等等,直到調用setter時。
自定義 Binding 類名稱
默認情況下,Binding類的命名是基於所述layout文件的名稱,用大寫開頭,除去下劃線()以及()後的第一個字母大寫,然後添加“Binding”後綴。這個類將被放置在一個模塊封裝包裏的databinding
封裝包下。例如,所述layout文件contact_item.xml
將生成ContactItemBinding
。如果模塊包是com.example.my.app
,那麼它將被放置在com.example.my.app.databinding
。
Binding類可通過調整data
元素中的class
屬性來重命名或放置在不同的包中。例如:
<data class="ContactItem">
...
</data>
在模塊封裝包的databinding包中會生成名爲ContactItem
的Binding類。如果要想讓該類生成在不同的包種,你需要添加前綴.
,如下:
<data class=".ContactItem">
...
</data>
在這個情況下,ContactItem
類直接在模塊包種生成。或者你可以提供整個包名:
<data class="com.example.ContactItem">
...
</data>
Includes
通過使用application namespace以及在屬性中的Variable名字從容器layout中傳遞Variables到一個被包含的layout:
<?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
兩個layout文件中必需要有user
variable
表達式
常用表達式跟Java表達式很像,以下這些是一樣的:
- 數學
+
-
/
*
%
- 字符串連接
+
- 邏輯
&&
||
- 二進制
&
|
^
- 一元運算
+
-
!
~
- 移位
>>
>>>
<<
- 比較
==
>
<
>=
<=
instanceof
- 分組
()
null
Cast
- 方法調用
- 數據訪問
[]
- 三元運算
?:
示例:
android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'
缺少的操作:
this
super
new
- 顯式泛型調用
Null合併操作
-
??
- 左邊的對象如果它不是null,選擇左邊的對象;或者如果它是null,選擇右邊的對象:android:text="@{user.displayName ?? user.lastName}"
函數上的寫法如下:
android:text="@{user.displayName != null ? user.displayName : user.lastName}"
屬性引用
第一個已經在前邊提到了a)Data Binding表達式
:JavaBean引用的簡短格式。
當一個表達式引用一個類的屬性,它仍使用同樣的格式對於字段、getters以及ObservableFields。
android:text="@{user.lastName}"
避免 NullPointerException
Data Binding代碼生成時自動檢查是否爲nulls來避免出現null pointer exceptions錯誤。例如,在表達式@{user.name}
中,如果user
是null,user.name
會賦予它的默認值(null)。如果你引用user.age
,age是int
類型,那麼它的默認值是0。
集合
常用的集合:arrays、lists、sparse lists以及maps,爲了簡便都可以使用[]
來訪問。
<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"]}"
Resources
使用正常的表達式來訪問resources也是可行的:
android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
格式化字符串和複數可以通過提供參數來判斷
android:text="@{@string/nameFormat(firstName, lastName)}"
android:text="@{@plurals/banana(bananaCount)}"
當複數需要多個參數時,所有的參數都會通過:
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 |
5. Data 對象
任何Plain old Java object(POJO)可用於Data Binding,但修改POJO不會導致UI更新。Data Binding的真正能力是當數據變化時,可以通知給你的Data對象。有三種不同的數據變化通知機制:Observable
對象、ObservableFields
以及observable
collections
。
當這些可觀察Data對象綁定到UI,Data對象屬性的更改後,UI也將自動更新。
Observable 對象
實現android.databinding.Observable
接口的類可以允許附加一個監聽器到Bound對象以便監聽對象上的所有屬性的變化。
Observable
接口有一個機制來添加和刪除監聽器,但通知與否由開發人員管理。爲了使開發更容易,一個BaseObservable
的基類爲實現監聽器註冊機制而創建。Data實現類依然負責通知當屬性改變時。這是通過指定一個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 getFirstName() {
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);
}
}
在編譯期間,Bindable
註解在BR類文件中生成一個Entry。BR類文件會在模塊包內生成。如果用於Data類的基類不能改變,Observable
接口通過方便的PropertyChangeRegistry
來實現用於儲存和有效地通知監聽器。
Observable 字段
一些小工作會涉及到創建Observable類,因此那些想要節省時間或者幾乎沒有幾個屬性的開發者可以使用ObservableFields
。ObservableFields
是自包含具有單個字段的observable對象。它有所有基本類型和一個是引用類型。要使用它需要在data對象中創建public
final字段:
private static class User extends BaseObservable {
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();
Observable 集合
一些app使用更多的動態結構來保存數據。Observable集合允許鍵控訪問這些data對象。ObservableArrayMap
用於鍵是引用類型,如String
。
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.put("age", 17);
在layout文件中,通過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"/>
ObservableArrayList
用於鍵是整數:
ObservableArrayList<Object> user = new ObservableArrayList<>();
user.add("Google");
user.add("Inc.");
user.add(17);
在layout文件中,通過索引可以訪問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"/>
6. Binding生成
Binding類的生成鏈接了layout中variables與Views。如前面所討論的,Binding的名稱和包名可以定製。所生成的Binding類都擴展了android.databinding.ViewDataBinding
。
創建
Binding應在inflation之後就立馬創建,以確保View層次結構不在之前打擾layout中的binding到views上的表達式。有幾個方法可以綁定到一個layout。最常見的是在Binding類上使用靜態方法.inflate
方法載入View的層次結構並且綁定到它只需這一步。還有一個更簡單的版本,只需要LayoutInflater
還有一個是採用ViewGroup
:
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater);
MyLayoutBinding binding = MyLayoutBinding.inflate(LayoutInflater, viewGroup, false);
如果使用不同的機制載入layout,他可一分開綁定:
MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);
有時Binding不能提前知道,對於這種情況,可以使用DataBindingUtil
類來創建Binding:
ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater, layoutId,
parent, attachToParent);
ViewDataBinding binding = DataBindingUtil.bindTo(viewRoot, layoutId);
帶ID的Views
在layout中對於每個帶ID的View會生成一個public final字段。Binding在View層次結構上做單一的傳遞,提取帶ID的Views。這種機制比起某些Views使用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;
IDs不像沒有Data Bindings那樣幾乎沒有必要,但是仍然會有一些實例需要從代碼中訪問Views。
Variables
每個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>
它會在Binding中生成setters和getters:
public abstract com.example.User getUser();
public abstract void setUser(com.example.User user);
public abstract Drawable getImage();
public abstract void setImage(Drawable image);
public abstract String getNote();
public abstract void setNote(String note);
ViewStubs
ViewStubs跟正常的Views略有不同。他們開始時是不可見的,當他們要麼設置爲可見或被明確告知要載入時,它們通過載入另外一個layout取代了自己。
由於ViewStub基本上從View的層次結構上消失,在Binding對象的View也必須消失來允許被收集。因爲Views是最後的,一個ViewStubProxy
對象取帶ViewStub,給開發者獲得了ViewStub,當它存在以及還可以訪問載入的View層次結構時當ViewStub已被載入時。
當載入另一個layout,爲新的佈局必需創建一個Binding。因此,ViewStubProxy
必需監聽ViewStub
的OnInflateListener
監聽器並在那個時候建立Binding。因爲只有一個可以存在,ViewStubProxy
允許開發者在其上設置一個OnInflateListener
它會在建立Binding後調用。
Binding進階
動態Variables
有時,不知道具體的Binding類,例如,一個RecyclerView
適配器對layouts任意操作並不知道具體的Binding類。它仍然必需在onBindViewHolder
期間賦值給Binding。
在這個例子中,該RecyclerView
綁定的所有layouts有一個“item”的Variable。該BindingHolder
有一個getBinding
方法返回ViewDataBinding
。
public void onBindViewHolder(BindingHolder holder, int position) {
final T item = mItems.get(position);
holder.getBinding().setVariable(BR.item, item);
holder.getBinding().executePendingBindings();
}
直接Binding
當一個variable或observable變化時,binding會在下一幀之前被計劃要改變。有很多次,但是在Binding時必須立即執行。要強制執行,使用executePendingBindings()
方法。
後臺線程
只要它不是一個集合,你可以在後臺線程中改變你的數據模型。在判斷是否要避免任何併發問題時,Data Binding會對每個Varialbe/field本地化。
7. 屬性Setters
每當綁定值的變化,生成的Binding類必須調用setter方法。Data Binding框架有可以自定義賦值的方法。
自動Setters
對於一個屬性,Data Binding試圖找到setAttribute
方法。與該屬性的namespace並不什麼關係,僅僅與屬性本身名稱有關。
例如,有關TextView的android:text
屬性的表達式會尋找一個setText(String)
的方法。如果表達式返回一個int
,Data
Binding會搜索的setText(int)
方法。注意:要表達式返回正確的類型,如果需要的話使用casting
。Data
Binding仍會工作即使沒有給定名稱的屬性存在。然後,您可以通過Data Binding輕鬆地爲任何setter“創造”屬性。例如,DrawerLayout
沒有任何屬性,但大量的setters。您可以使用自動setters來使用其中的一個。
<android.support.v4.widget.DrawerLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:scrimColor="@{@color/scrim}"
app:drawerListener="@{fragment.drawerListener}"/>
重命名的Setters
一些有setters的屬性按名稱並不匹配。對於這些方法,屬性可以通過BindingMethods
註解相關聯。這必須與一個包含BindingMethod
註解的類相關聯,每一個用於一個重命名的方法。例如,android:tint
屬性與setImageTintList
相關聯,而不與setTint
相關。
@BindingMethods({
@BindingMethod(type = "android.widget.ImageView",
attribute = "android:tint",
method = "setImageTintList"),
})
以上例子,開發者需要重命名setters是不太可能了,android架構屬性已經實現了。
自定義Setters
有些屬性需要自定義綁定邏輯。例如,對於android:paddingLeft
屬性並沒有相關setter。相反,setPadding(left,
top, right, bottom)
是存在在。一個帶有BindingAdapter
註解的靜態綁定適配器方法允許開發者自定義setter如何對於一個屬性的調用。
Android的屬性已經創造了BindingAdapters
。舉例來說,對於paddingLeft
:
@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int padding) {
view.setPadding(padding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom());
}
Binding適配器對其他定製類型非常有用。例如,自定義loader可以用來異步載入圖像。
當有衝突時,開發人員創建的Binding適配器將覆蓋Data Binding默認適配器。
您也可以創建可以接收多個參數的適配器。
@BindingAdapter({"bind:imageUrl", "bind:error"})
public static void loadImage(ImageView view, String url, Drawable error) {
Picasso.with(view.getContext()).load(url).error(error).into(view);
}
<ImageView app:imageUrl=“@{venue.imageUrl}”
app:error=“@{@drawable/venueError}”/>
如果對於一個ImageView
imageUrl和error都被使用並且imageUrl
是一個string類型以及error是一個drawable時,該適配器會被調用。
- 匹配的過程中自定義namespaces將被忽略。
- 你也可以爲Android namespaces寫適配器。
8. 轉換
對象轉換
當從Binding表達式返回一個對象,一個setter會從自動、重命名以及自定義的setters中選擇。該對象將被轉換爲所選擇的setter的參數類型。
這是爲了方便那些使用ObservableMaps
來保存數據。例如:
<TextView
android:text='@{userMap["lastName"]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
在userMap
返回一個對象並且該對象將自動轉換爲setText(CharSequence)
的參數類型。當有關參數類型可能混亂時,開發人員需要在表達式中轉換。
自定義轉換
有時候轉換應該是自動的在特定類型之間。例如,設置背景的時候:
<View
android:background="@{isError ? @color/red : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
這裏,背景需要Drawable
對象,但顏色是一個整數。不管何時有Drawable
並且返回值是一個整數,那麼整數類型會被轉換爲ColorDrawable
。這個轉換是通過使用帶有BindingConversion
註解的靜態方法完成的:
@BindingConversion
public static ColorDrawable convertColorToDrawable(int color) {
return new ColorDrawable(color);
}
注意:轉換僅僅發生在setter級別,因此它是不允許以下混合類型:
<View
android:background="@{isError ? @drawable/error : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
---------------------<完>-----------------------