2015年12月24日
[TOC]
1换吧、環(huán)境需要:
1.Android 2.1 (API level 7+)
2.Gradle 1.5.0-alpha1
3.Android Studio 1.3
2沾瓦、環(huán)境搭建
在build.gradle的android中加入如下字段,等待系統(tǒng)重新編譯贯莺。
android{
...
dataBinding {
enabled = true
}
...
}
3宁改、快速開始
1、編寫布局布局文件
和傳統(tǒng)的布局文件不同爹耗,databinding的布局文件的跟標(biāo)簽為layout
,他有兩個(gè)子標(biāo)簽潭兽,分別為data
和原始布局標(biāo)簽锅论,也就是說在原來的布局基礎(chǔ)上多加了一層layout
,然后里面又多了一個(gè)data
標(biāo)簽最易。在寫完布局文件之后別忘記MakeProject一下,以便系統(tǒng)自動(dòng)生成對應(yīng)的類剔猿,類名為布局文件的名字首字母大寫归敬。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 配置變量汪茧,name字段為下面想要引用的類舱污,type為全類名,
AS中快捷鍵ctrl+shift+alt+c -->
<data>
<variable
name="person"
type="com.znke.hellodatabinding.Person"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 需要填充的字段用@{}表示 -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25sp"
android:text="@{person.name}"
/>
<!-- 這里要轉(zhuǎn)換一下,不然會(huì)引用int值所對應(yīng)的R文件中的id -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25sp"
android:text="@{String.valueOf(person.age)}"
/>
</LinearLayout>
</layout>
2珠插、編寫數(shù)據(jù)對象
一個(gè)簡單POJO即可
public class Person {
public final String name;
public final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
3、在Acticity中進(jìn)行綁定
在Acticity的onCreate(一個(gè)參數(shù))方法里面進(jìn)行綁定捻撑。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//當(dāng)編寫完布局文件的時(shí)候,他會(huì)自動(dòng)生成一個(gè)對應(yīng)的類布讹,名字為布局文件名稱+Binding
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
Person person = new Person("liucl", 22);
//綁定
binding.setPerson(person);
}
*** 注意:***編譯過中程如果出現(xiàn)xxx.databingding不存在琳拭,那么就是你布局文件寫錯(cuò)了描验。仔細(xì)檢查坑鱼,現(xiàn)在as還不支持語法提示呼股。
運(yùn)行正常如下:
成功了,就是這三步2帧O猎啊唱矛!
4管闷、綁定點(diǎn)擊事件
Databinding支持把事件綁定到對象中窃肠,使用方法和上面大同小異
1铭拧、編寫事件對象
public class ClickEvent {
public void click(View v){
Toast.makeText(v.getContext(), "測試成功 \n Context對象為"
+ v.getContext().toString()
+ "\n View對象為"
+ v.toString(),
Toast.LENGTH_SHORT).show();
}
}
在這里我們吐司出v所在Context對象和View對象以及他所屬的布局呕臂。
2、修改我們的布局文件
首先新建一個(gè)variable
引入這個(gè)類谜洽。在data
字段中加入
<variable
name="event"
type="com.znke.hellodatabinding.ClickEvent"/>
其實(shí),我們可以使用import
直接導(dǎo)入這個(gè)類实束,值得注意的是咸灿,這個(gè)區(qū)別于java
的import
關(guān)鍵字,java
中這個(gè)是導(dǎo)入包审胸,而這個(gè)是導(dǎo)入類歹嘹。完整的data
代碼如下:
<data>
<import type="com.znke.hellodatabinding.Person"/>
<import type="com.znke.hellodatabinding.ClickEvent"/>
<variable
name="person"
type="Person"/>
<variable
name="event"
type="ClickEvent"/>
</data>
之后材蛛,我們在布局文件中加入一個(gè)Button
,在onClick
屬性中引用這個(gè)類
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="測試"
android:onClick="@{event.click}"/>
最后別忘記在Acticity中綁定!6股汀!
...
binding.setEvent(new ClickEvent());
...
運(yùn)行正常如下:
5、Include對象傳遞
Databinding支持include對象傳遞宣蔚,在A布局里面的對象可以傳遞到他include進(jìn)來的布局,
- 在A布局里定義號自定義命名空間。
xmlns:app="http://schemas.android.com/apk/res-auto"
下面要用到亩冬。 - A布局里面的include標(biāo)簽
<include layout="@layout/include_click"
app:event="@{event}"/>
- B布局代碼
在B中也要引用一個(gè)傳遞過來的類,這個(gè)布局不用在Acticity中綁定。看過這個(gè)代碼之后巍糯,你可能回想怎么不用merge
優(yōu)化呢祟峦,——暫時(shí)不支持
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="event"
type="com.znke.hellodatabinding.ClickEvent"/>
</data>
<!-- 暫不支持merge標(biāo)簽 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="測試"
android:onClick="@{event.click}"/>
</LinearLayout>
</layout>
6、表達(dá)式符號
布局文件支持這些表達(dá)式距淫,我直接引用谷歌文檔
https://developer.android.com/tools/data-binding/guide.html
Mathematical + - / * %
String + 這個(gè)符號可能會(huì)引起引號沖突,需把文字放到資源文件
Logical && ||
Binary & | ^
Unary + - ! ~
Shift >> >>> <<
Comparison == > < >= <=
instanceof
Grouping ()
Literals - character, String, numeric, null
Cast
Method calls
Field access
Array access []
Ternary operator ?:
7、綁定對象與視圖堂污,使他們能聯(lián)動(dòng)
通過更改對象,視圖自動(dòng)就會(huì)隨之改變式镐,這個(gè)功能實(shí)現(xiàn)View與model層邏輯代碼的解耦和。
谷歌給出兩種方法
- Observable Objects
將你的POJO繼承BaseObservable,這個(gè)類實(shí)現(xiàn)了Observable禽作。可以實(shí)現(xiàn)POJO值改變幢妄,framework層會(huì)自動(dòng)更新布局文件數(shù)據(jù)
private static class Person extends BaseObservable {
private String name;
private String age;
@Bindable
public String getName() {
return name;
}
@Bindable
public String getAge() {
return age;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
public void setAge(String age) {
this.age = age;
notifyPropertyChanged(BR.age);
}
}
- ObservableFields
其實(shí)他繼承了BaseObservable這個(gè)類忍法,在他的泛型中添上你的類型衍锚。同時(shí)
ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble,ObservableParcelable
也都是繼承了BaseObservable。
public class Person {
public ObservableField<String> name = new ObservableField<>();
public ObservableInt age = new ObservableInt();
}
注:谷歌文檔也給了一個(gè)Observable Collections,但我沒試驗(yàn)成功后专,但是使用上面那個(gè)方法,是可以實(shí)現(xiàn)集合更改的。
通過上面的修改后甘畅,無論在那里改這個(gè)對象里面的值函似,相應(yīng)的布局文件里面的引用都會(huì)隨之改變准给。
8、拋棄你的findViewById()
有了Databinding
再也不用謝冗長的findViewById()了,框架會(huì)為你自動(dòng)生成的BR文件。
首先在我們的布局文件中莫绣,為我們兩個(gè)TextView
加上id
,回到Acticity中的Binding對象,是不是多出了兩個(gè)屬性。
binding.tvText1.setText("");
binding.tvText2.setText("");
這樣你就可以直接給他設(shè)置文本了,但是有一種更好的方法,直接binding.setVariable(com.znke.hellodatabinding.BR.person,new Person());
就可以直接給布局文件中的變量賦值。
BR存儲了布局中
data
標(biāo)簽中的variable
,相當(dāng)于R文件剿骨。
9、Attribute Setters(屬性設(shè)置)
這東西就好像Button里面的onClick屬性嫡秕,然后給他在Acticity里面寫一個(gè)對應(yīng)的實(shí)現(xiàn)方法牙甫。他的強(qiáng)大之處就是它可以什么都向里面設(shè)置。不關(guān)是點(diǎn)擊事件。他對于的實(shí)現(xiàn)方法只需要用一個(gè)注解聲明就可以了阿蝶,寫在那里都可以爽丹,即使是一個(gè)沒有使用的java文件。
通過一個(gè)Demo來說明碑宴,他有一個(gè)輸入框延柠,輸入框輸入文字雹仿,上面的TextView
也會(huì)隨之改變胧辽,這里用到了屬性設(shè)置
和對象綁定
。
布局代碼
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="輸入內(nèi)容"
app:textwatcher="@{person}"/>
屬性設(shè)置代碼
public class BindingAdapter {
private static final String TAG = BindingAdapter.class.getSimpleName();
/**
* 添加上這個(gè)注解悄蕾,方法為靜態(tài)無返回值票顾,
* 方法有兩個(gè)參數(shù)础浮,第一個(gè)是控件本身帆调,第二個(gè)為傳進(jìn)來的對象
* 注意這個(gè)方法會(huì)被調(diào)用多次,其中會(huì)有對象為空的情況。So...
*
* @param e 控件本身
* @param person 傳進(jìn)來的對象
*/
@android.databinding.BindingAdapter({"app:textwatcher"})
public static void editTextWatcher(final EditText e,final Person person) {
if (person != null) {
e.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
person.name.set(s.toString());
e.setSelection(s.length());
}
});
}
}
}
BindingAdapter生命周期所在
在View
所在Activity
的onCreate
方法之后豆同。當(dāng)然番刊,自定義監(jiān)聽除外
12-21 11:39:51.289 3388-3388/? E/TAG: onFinishInflate:
12-21 11:39:51.295 3388-3388/? E/TAG: onCreate: null
12-21 11:39:51.331 3388-3388/? E/TAG: initAdapter:
12-21 11:39:51.331 3388-3388/? E/TAG: initManager:
12-21 11:39:51.333 3388-3388/? E/TAG: onAttachedToWindow:
12-21 11:39:51.338 3388-3388/? E/TAG: onMeasure:
12-21 11:39:51.406 3388-3388/? E/TAG: onLayout:
12-21 11:39:51.429 3388-3388/? E/TAG: onMeasure:
12-21 11:39:51.431 3388-3388/? E/TAG: onLayout:
12-21 11:39:51.433 3388-3388/? E/TAG: onDraw:
12-21 11:39:51.502 3388-3388/? E/TAG: onMeasure: