編輯:關於Android編程
Data binding 在2015年7月發布的Android Studio v1.3.0 版本上引入,在2016年4月Android Studio v2.0.0 上正式支持。目前為止,Data Binding 已經支持雙向綁定了。
Databinding 是一個實現數據和UI綁定的框架,是一個實現 MVVM 模式的工具,有了 Data Binding,在Android中也可以很方便的實現MVVM開發模式。
Data Binding 是一個support庫,最低支持到Android 2.1(API Level 7+)。
Data Binding 之前,我們不可避免地要編寫大量的重復的代碼,如 findViewById()、setText(),setVisibility(),setEnabled() 或 setOnClickListener() 等,通過 Data Binding , 我們可以通過聲明式布局以精簡的代碼來綁定應用程序邏輯和布局,這樣就不用編寫大量的重復的代碼了。
1.在模塊的build.gradle文件中添加dataBinding配置
android { ...... dataBinding{ enabled = true } ...... }
注意:如果app依賴了一個使用 Data Binding 的庫,那麼app module 的 build.gradle 也必須配置 Data Binding
Data binding 的布局文件與傳統布局文件有一點不同。它以一個 layout 標簽作為根節點,裡面是 data 標簽與 view 標簽。view 標簽的內容就是不使用 Data Binding 時的普通布局文件內容。以下是一個例子:
activity_main.xml
在上面的布局中,對於data裡面的variable nama=”entry”表示的是一個變量名entry,type表示你所對應實體的包名路徑,在TextView中,我們采用@{}的語法來引用實體類Entry中的屬性。
Entry.java
public class Entry { private String text; private int color; public String getText() { return text; } public void setText(String text) { this.text = text; } public int getColor() { return color; } public void setColor(int color) { this.color = color; } }
上面就是我們所說的實體類Entry,用於TextView的android:text屬性的表達式
@{entry.text}和
android:textColor屬性表達式
@{entry.color}
綁定數據 - (ViewModel)
在默認情況下,會基於布局文件生成一個繼承於 ViewDataBinding 的 Binding 類,將它轉換成和你的布局命名並在名字後面接上Binding。例如,布局文件叫 activity_main.xml,所以會生成一個 ActivityMainBinding類。這個類包含了布局文件中所有的綁定關系,會根據綁定表達式給布局文件賦值。在 inflate 的時候創建 binding 的方法如下:
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
Entry entry = new Entry();
entry.setText("文本數據1");
entry.setColor(0xff0000ff);
binding.setEntry(entry);
}
}
事件處理
類似於 android:onClick 可以指定 Activity 中的函數,Data Binding 也允許處理從視圖中發送的事件。
有兩種實現方式:
方法調用
監聽綁定
二者主要區別在於方法調用在編譯時處理,而監聽綁定於事件發生時處理。
方法調用
相較於 android:onClick ,它的優勢在於表達式會在編譯時處理,如果函數不存在或者函數簽名不對,編譯將會報錯。
以下是個例子:
Entry.java
public class Entry {
private String text;
private int color;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
//在這個實體中添加一個點擊時間的方法
public void onClick(View view){
Toast.makeText(view.getContext(),"已點擊",Toast.LENGTH_SHORT).show();
}
}
activity_main.xml
通過在上面的TextView中添加一個
android:onClick屬性表達式為
@{entry.onClick}這樣就能調用點擊事件 了,(注意:對應的方法名和監聽器對象必須對應) 如果該方法不存在,則在編譯的時候就不會通過了。除了上面的表達式可以表示之外,我們還可以使用以下的表達式方式進行設置:
android:onClick="@{entry.onClick}"(不過這種方式已經過時了,因為這樣的表示會和entry.text這樣的屬性引用難以區分)
監聽綁定
監聽綁定在事件發生時調用,可以使用任意表達式
此功能在 Android Gradle Plugin version 2.0 或更新版本上可用.
在方法引用中,方法的參數必須與監聽器對象的參數相匹配。在監聽綁定中,只要返回值與監聽器對象的預期返回值相匹配即可。
Entry.java
public class Entry {
private String text;
private int color;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
//將點擊監聽事件中添加了一個參數
public void onClick(View view,String str){
Toast.makeText(view.getContext(),"已點擊,產生了" + str,Toast.LENGTH_SHORT).show();
}
}
activity_main.xml
MainAcitivty.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main,new MyComponent(this));
Entry entry = new Entry();
entry.setText("文本數據1");
entry.setColor(0xff0000ff);
//設置測試字符串
binding.setStr("我是監聽綁定的數據測試");
binding.setEntry(entry);
}
}
當一個回調函數在表達式中使用時,數據綁定會自動為事件創建必要的監聽器並注冊監聽。關於
android:onClick="@{(v) -> entry.onClick(v,str)}"這裡采用的是java1.8中的lambda表達式的形式,因為這樣我們可以傳遞相應的參數進去。
導入(Imports)
1.data 標簽內可以有多個 import 標簽。你可以在布局文件中像使用 Java 一樣導入引用
activity_main.xml
2.當類名發生沖突時,可以使用 alias
3.導入的類型也可以用於變量的類型引用和表達式中
注意:Android Studio 還沒有對導入提供自動補全的支持。你的應用還是可以被正常編譯,要解決這個問題,你可以在變量定義中使用完整的包名。
4.導入也可以用於在表達式中使用靜態方法
StringUtils.java
public class StringUtils {
public static String show(String string){
string = string.toUpperCase();
return string;
}
}
activity_main.xml
......
5.java.lang.* 包中的類會被自動導入,可以直接使用,例如, 要定義一個 String 類型的變量
變量 Variables
1.data 標簽中可以有任意數量的 variable 標簽。每個 variable 標簽描述了會在 binding 表達式中使用的屬性。
2.可以在表達式中直接引用帶 id 的 view,引用時采用駝峰命名法。
3.binding 類會生成一個命名為 context 的特殊變量(其實就是 rootView 的 getContext() ) 的返回值),這個變量可用於表達式中。 如果有名為 context 的變量存在,那麼生成的這個 context 特殊變量將被覆蓋。
StringUtils.java
public class StringUtils {
public static String show(Context context,String string){
Toast.makeText(context, string,Toast.LENGTH_SHORT).show();
string = string.toUpperCase();
return string;
}
}
......
自定義綁定類名
默認情況下,binding 類的名稱取決於布局文件的命名,以大寫字母開頭,移除下劃線,後續字母大寫並追加 “Binding” 結尾。這個類會被放置在 databinding 包中。舉個例子,布局文件 activity_main.xml 會生成 ActivityMainBinding 類。如果 module 包名為 com.example.my.app ,binding 類會被放在 com.example.my.app.databinding 中。
通過修改 data 標簽中的 class 屬性,可以修改 Binding 類的命名與位置。舉個例子:
...
以上會在 databinding 包中生成名為 CustomBinding 的 binding 類。如果需要放置在不同的包下,可以在前面加 “.”:
...
這樣的話, CustomBinding 會直接生成在 module 包下。如果提供完整的包名,binding 類可以放置在任何包名中:
...
Includes
include.xml
需要注意, activity_main.xml 與 include.xml 中都需要聲明 user 變量。
Data binding 不支持直接包含 merge 節點。舉個例子, 以下的代碼不能正常運行 :
表達式語言
表達式語言與 Java 表達式有很多相似之處。下面是相同之處:
數學計算 + - / * % 字符串連接 + 邏輯 && || 二進制 & | ^ 一元 + - ! ~ 位移 >> >>> << 比較 == > < >= <= instanceof 組 () 字面量 - 字符,字符串,數字, null 類型轉換 函數調用 字段存取 數組存取 [] 三元運算符 ?:
在xml中轉義是不可避免的,如 : 使用“&&”是編譯不通過的,需要使用轉義字符 “&&”
附:常用的轉義字符
描述
轉義字符
十進制
顯示結果
空格
;
;
小於號
<;
<;
<
大於號
>;
>;
>
與號
&;
&;
&
引號
";
";
"
撇號
&apos;
';
'
乘號
×;
×;
×
除號
÷;
÷;
÷
不支持的操作符
一些 Java 中的操作符在表達式語法中不能使用。
this super new 顯示泛型調用
Null合並運算符
Null合並運算符 ?? 會在非 null 的時候選擇左邊的操作,反之選擇右邊。
android:text="@{entry.text ?? `Default Text`}"
等同於
android:text="@{entry.text != null ? entry.text : `Default Text`}"
容器類
通用的容器類:數組,List ,SparseArray ,和 Map,可以用 [] 操作符來存取
…
android:text="@{list[index]}"
…
android:text="@{sparse[index]}"
…
android:text="@{map[key]}"
字符串常量
使用單引號把屬性包起來,就可以很簡單地在表達式中使用雙引號:
android:text='@{map["text"]}'
也可以用雙引號將屬性包起來。這樣的話,字符串常量就可以用 ” 或者反引號 ( ` ) 來調用
android:text="@{map[`text`}"
android:text="@{map["text"]}"
資源
也可以在表達式中使用普通的語法來引用資源:
android:text="@{@string/text(entry.text)"
字符串格式化和復數形式可以這樣實現:
android:text="@{@plurals/sample_plurals(num)}"
當復數形式有多個參數時,應該這樣寫:
android:text="@{@plurals/numbers(num, num)}"
Type
Normal Reference
Expression Reference
String[]
@array
@stringArray
int[]
@array
@intArray
TypedArray
@array
@typedArray
Animator
@animator
@animator
StateListAnimator
@animator
@stateListAnimator
color int
@color
@color
ColorStateList
@color
@colorStateList
數據對象 (Data Objects)
任何 POJO 對象都能用在 Data Binding 中,但是更改 POJO 並不會同步更新 UI。Data Binding 的強大之處就在於它可以讓你的數據擁有更新通知的能力。
Observable 對象
Observable 字段
Observable 容器類
當以上的 observable 對象綁定在 UI 上,數據發生變化時,UI 就會同步更新。
Observable 對象
Observable 接口有一個添加/移除 listener 的機制,但通知取決於開發者。為了簡化開發,Android 原生提供了一個基類 BaseObservable 來實現 listener 注冊機制。這個類也實現了字段變動的通知,只需要在 getter 上使用 Bindable 注解,並在 setter 中通知更新即可。
public class Entry extends BaseObservable{
private String text;
private int color;
@Bindable
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
notifyPropertyChanged(BR.text);
}
@Bindable
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
notifyPropertyChanged(BR.color);
}
public void onClick(View view,String str){
Toast.makeText(view.getContext(),"已點擊,產生了" + str,Toast.LENGTH_SHORT).show();
setText(str);
setColor(0xffff0000);
}
}
BR 是編譯階段生成的一個類,功能與 R.java 類似,用 @Bindable 標記過 getter 方法會在 BR 中生成一個 entry。
當點擊 事件使數據發生變化時需要調用 notifyPropertyChanged(BR.text) 通知系統 BR.text 這個 entry 的數據已經發生變化以更新UI。
ObservableFields
創建 Observable 類還是需要花費一點時間的,如果想要省時,或者數據類的字段很少的話,可以使用 ObservableField 以及它的派生 ObservableBoolean、ObservableByte 、ObservableChar、ObservableShort、ObservableInt、ObservableLong、ObservableFloat、ObservableDouble、
ObservableParcelable 。
ObservableFields 是包含 observable 對象的單一字段。原始版本避免了在存取過程中做打包/解包操作。要使用它,在數據類中創建一個 public final 字段:
public class EntryField{
public ObservableField mText = new ObservableField<>();
public ObservableField mColor = new ObservableField<>();
public EntryField(String text, int color) {
mText.set(text);
mColor.set(color);
}
}
要存取數據,只需要使用 get() / set() 方法:
mEntryField.mText.set("text");
mEntryField.mColor.set(0xffff0000);
String text = mEntryField.mText.get();
String color = mEntryField.mColor.get();
Observable Collections 容器類
一些應用會使用更加靈活的結構來保持數據。Observable 容器類允許使用 key 來獲取這類數據。當 key 是類似 String 的一類引用類型時,使用 ObservableArrayMap 會非常方便。
ObservableArrayMap mEntry = new ObservableArrayMap<>();
mEntry .put("text", "it_real_man");
mEntry .put("color", 0xffff0000);
binding.setEntry(mEntry);
在布局中,可以用 String key 來獲取 map 中的數據:
…
當 key 是整數類型時,可以使用 ObservableArrayList :
ObservableArrayList sEntry= new ObservableArrayList<>();
sEntry.add("entryData");
sEntry.add("text");
sEntry.add("color");
binding.setSEntry(sEntry);
在布局文件中,使用下標獲取列表數據:
…
(一)前言今天我們一起來看一下工具欄控件ToolBarAndroid的介紹完全解析以及最佳實踐。剛創建的React Native技術交流群(282693535),歡迎各位
魅族MX6已發布了,除了漂亮的外觀,MX6還帶來了一項重磅功能:微信指紋支付(此前已經支持支付寶)。那魅族微信指紋支付是怎麼支付的呢?下文就讓小編跟大家魅族
因為項目中需要用到所以實現的一個橫向的照片浏覽器,使用橫向SrollView實現。實現效果如下:實現思路:在開始做之前呢,本著有輪子就用輪子的精神,也還是去百度找了很久,
當用戶輸入一定的字符之後,自動完成文本框能夠顯示一個下拉菜單,供用戶從中選擇,當用戶選擇某個菜單項之後,AutoCompleteTextView可以按照用戶的選擇自動填寫