最近在學(xué)習(xí)DataBinding的使用生宛,中間遇到了不少的坑县昂,記錄以下,幫助以后學(xué)習(xí)DataBinding的朋友陷舅。
一:引入
其實(shí)倒彰,我們只需要在對(duì)應(yīng)的Module的build.gradle中添加這么一句話即可。
dataBinding {
enabled=true
}
不需要加別的東西莱睁。
二:簡單使用的時(shí)候我出現(xiàn)的錯(cuò)誤
1.比如這么寫
android:text="@{User.name}"/>
那么狸驳,我User中的成員變量name,必須是String類型的缩赛。因?yàn)镈ataBinding不是使用反射的耙箍,你必須公有化才能訪問得到。否則會(huì)報(bào)找不到類酥馍,···javac什么的異常辩昆。
2.比如我這么寫
android:text="@{User.age}
那么,我的age這個(gè)成員變量必須是String類型的旨袒,如果使用int類型的話汁针,程序會(huì)crash掉
但如果必須是int類型,那么該怎么寫呢砚尽,可以這么寫
android:text="@{String.valueOf(user.age)}"
因?yàn)檫@個(gè)android:text 中是 String 類型
3.比如我這么寫
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
ActivityMainBinding這個(gè)類又是來自于哪里施无?他是根據(jù)R.layout.activity_main來生成的。如果我的布局文件是main_activity,那么就應(yīng)該生成MainActivityBinding必孤。
三:開始使用
引入DataBinding的時(shí)候我遇到過以上的錯(cuò)誤猾骡,之后就讓我們一起學(xué)習(xí)DataBinding的使用吧。
我推薦大家把這個(gè)Demo下載下來敷搪,跟著源碼去讀一讀兴想,感受一下功能和寫法
DataBindingDemo
而今天,我們就是去Read The Fucking Source Code赡勘。
首頁是這樣的嫂便,我們一個(gè)一個(gè)進(jìn)去看
1:A SIMPLE BASIC EXAMPLE
這個(gè)比較簡單,建議讀者自己能跟著代碼走一遍闸与,有什么不懂得可以留言毙替,我們一起探討進(jìn)步。
說幾個(gè)需要注意的地方
android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"http://支持三元運(yùn)算符践樱。需要導(dǎo)入View包
android:text="@{String.valueOf(user.age)}"http://前面說了厂画,@{只能是String},為什么映胁,可以看3.1木羹,匹配規(guī)則
android:text="@{StringUtils.capitalize(user.firstName)}"http://前面導(dǎo)入了這個(gè)包,可以調(diào)用這個(gè)靜態(tài)方法
android:text="@{user.displayName ?? user.lastName}"http://它表達(dá)的是如果左邊不是 null 的,那么使用左邊的值坑填,否者使用右邊的值抛人。在棉花糖的文章里有介紹
2:CustomBinding
這個(gè)的重點(diǎn)在這里
ContractBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_custom_binding);
看到了沒,xml是activity_custom_binding脐瑰,但是這個(gè)類卻是ContractBinding
他是在這里聲明過了的
data class=".ContractBinding"http://除了使用框架自動(dòng)ActivityCustomBinding妖枚,我們也可以通過這種方式自定義類名
3:INCLUDES
從這里開始要說的東西就多了。苍在。绝页。。建議剛?cè)腴T的讀者能耐心的看完
3.1萬物皆對(duì)象
不知道讀者有沒有想過寂恬,為什么binding這個(gè)對(duì)象會(huì)有binding.setUser()這個(gè)方法呢续誉?而我們當(dāng)前看的這個(gè)Activity為什么會(huì)有
binding.setListener(this);
binding.setOkText("to toast");
這兩個(gè)方法呢?
因?yàn)槲覀冊(cè)赿ata中聲明過這些東西
<data>
<import type="com.liangfeizc.databinding.model.User" />
<variable
name="user"
type="User" />
<variable
name="listener"
type="com.liangfeizc.databinding.listener.OkListener" />
<variable
name="okText"
type="String" />
</data>
name中標(biāo)識(shí)的user,listener初肉,okText酷鸦,就是binding所具有的屬性,而屬性就應(yīng)該具有set.get方法牙咏,這就是萬物皆對(duì)象臼隔,而后面的type,就是屬性名的類型妄壶。這么說理解嗎摔握?很簡單,把Binding當(dāng)做一個(gè)對(duì)象丁寄,萬物迎刃而解氨淌。
還有一處用到這個(gè)思想,問題迎刃而解狡逢,我們看include這個(gè)布局宁舰,有三個(gè)自定義的命名空間:
bind:user="@{user}"
bind:okText="@{okText}"
bind:listener="@{listener}"
這就是給他賦值的。這里奢浑,我推薦大家看一下https://realm.io/cn/news/data-binding-android-boyar-mount/
棉花糖的對(duì)自動(dòng)屬性的介紹。然后我說一下我的理解腋腮。
<variable
name="user"
type="com.liangfeizc.databinding.model.User" />
首先聲明這一個(gè)變量雀彼,讓我們的Binding對(duì)象具備了
private User user;
這一個(gè)屬性,而我在布局文件中,可以任意的使用我自己的成員變量user即寡。
這個(gè)時(shí)候徊哑,我可以自定義一個(gè)命名空間,并給我的任意控件添加任意屬性
比如說
<include
layout="@layout/layout_btn_ok"
bind:okText="@{okText}"
bind:listener="@{listener}"/>
<include>這個(gè)標(biāo)簽怎么會(huì)有這兩個(gè)屬性聪富,毫無疑問是自動(dòng)加上去的莺丑。那么它又該如何理解呢?
我們使用了 bind:okText這個(gè)屬性,但實(shí)際上該標(biāo)簽并沒有提供這么一個(gè) xml 布局屬性梢莽。這個(gè)時(shí)候我們就可以想一想自動(dòng)綁定萧豆。xml屬性不也是對(duì)象的一個(gè)屬性嗎?既然是屬性昏名,那么就有set,get涮雷。那么我們可以這么想,
private String okText;//如果我后面的@{okText}轻局,就是String類型的我就會(huì)自動(dòng)匹配過去洪鸭。
private OkListener listener;//如果我后面的@{listener},就是OkListener類型的我也會(huì)自動(dòng)匹配過去仑扑。
不知道這么說大家有沒有理解览爵。這里不好想,一定要自己多看幾遍代碼镇饮,多思考一下拾枣。慢慢來。沒必要急躁盒让。
3.2···id的作用
不知道大家有沒有為這種寫法而感到詫異
binding.layoutInput.etName.addTextChangedListener(null);
我去這是什么懊贩簟!~這是id邑茄。我們可以ctrl點(diǎn)進(jìn)去看一看姨蝴。
android:id="@+id/layout_input"
android:id="@+id/et_name"
只要給 View 定義一個(gè) ID,Data Binding 就會(huì)為我們生成一個(gè)對(duì)應(yīng)的 final變量肺缕。以_為單詞的分隔符左医,命名符合java規(guī)范。
3.3 點(diǎn)擊事件
如果大家看過棉花糖的教程同木,就會(huì)看浮梢,這是什么啊,就不能說的細(xì)一點(diǎn)嗎彤路?
<Button android:onClick="clicked" …/>
<Button android:onClick="@{handlers.clicked}" …/>
<Button android:onClick="@{isAdult ? handlers.adultClick :handlers.childClick}" …/>
<Button android:onTextChanged="@{handlers.textChanged}" …/>
其實(shí)不難想秕硝。第一個(gè)就是我們平常最常用的點(diǎn)擊事件的寫法,和databinding沒有關(guān)系啊洲尊。
剩下的都是一個(gè)模子出來的远豺。
官方的建議是將事件都寫到一起。
就比如代碼的作者是這么寫的
public interface OkListener {
void onClickOk(View view);}
然后讓
android:onClick="@{listener.onClickOk}"
在執(zhí)行時(shí)候就和我們平時(shí)使用差不多了
binding.setListener(this);
就這幾步坞嘀,讓你省去了fbc的煩惱躯护。不過,我寧愿想給每一個(gè)按鈕寫一個(gè)ID丽涩,我也不想給每一個(gè)按鈕寫一個(gè)方法名9字汀!!
3.3 include
其實(shí)說了那么多继准,到現(xiàn)在才進(jìn)入正題枉证。不知道您又學(xué)會(huì)了多少,學(xué)習(xí)千萬別急锰瘸,慢慢來刽严,別人的東西只能給你說以下有這么一個(gè)東西,具體的還是需要自己多思考的避凝。
閑話:曾經(jīng)我一直覺得舞萄,啊,我會(huì)這么多三方庫管削,什么功能都能實(shí)現(xiàn)倒脓,我要上天了。雖說君子善假于物也含思,但輪子誰都會(huì)滾崎弃,卻不是我這樣的坐井觀天,沾沾自喜含潘,僅會(huì)簡單的使用饲做。我現(xiàn)在想要改變這種狀況,嘗試著去讀各種demo的源碼遏弱,有時(shí)候也是看的頭蒙蒙的盆均,感覺會(huì)的越來越少,也有些急躁漱逸,一旦急躁什么東西都是學(xué)不下去的····難受極了泪姨。不過,我現(xiàn)在放正了心態(tài)饰抒,慢慢來學(xué)肮砾,緩慢而不懈怠,總有一天袋坑,一通百通仗处。共勉,加油咒彤,我們是第一疆柔,我們是最棒的!O庵!
說了這么多閑話模叙,其實(shí)是為了掩飾我內(nèi)心的恐懼歇拆,因?yàn)槲腋静恢溃瑸槭裁匆趇nclude引用的布局內(nèi)再寫一遍data啊故觅!
我是這么猜測(cè)的:
數(shù)據(jù)綁定厂庇,一個(gè)大布局對(duì)應(yīng)一個(gè)數(shù)據(jù)源。比如說我這個(gè)數(shù)據(jù)源有5份數(shù)據(jù)输吏,我這個(gè)大布局中有三個(gè)小布局权旷,第一個(gè)小布局需要1份數(shù)據(jù),第二個(gè)需要兩份數(shù)據(jù)贯溅,第三個(gè)需要5份數(shù)據(jù)拄氯。我可以按照這三個(gè)小布局聲明的需求來去給他們分配。而分配這個(gè)動(dòng)詞它浅,就對(duì)應(yīng)了3.1中的自動(dòng)屬性來解決译柏,就是填充!
而且可以保證數(shù)據(jù)源相對(duì)于這個(gè)布局的唯一姐霍。
我是這么猜的不知道你們那鄙麦。
include就說這么多,還需要再看镊折,這一個(gè)代碼寫的很好看胯府。
4.Collection
這里講的是集合作為數(shù)據(jù)源的使用,集合作為數(shù)據(jù)源用到的地方還是蠻多的恨胚。
4.1需要注意的地方
java.lang包下的類峭咒,如String什么的俐末,在data中是不需要導(dǎo)包的。
需要用轉(zhuǎn)義符& lt;來代替<,
4.2使用
其實(shí)有了上面的基礎(chǔ),在這里學(xué)習(xí)就很簡單了试幽,雖然代碼寫的很嚇人,各種轉(zhuǎn)義符匿值,但是其實(shí)就是一點(diǎn)灿巧,單列集合可以通過索引找到值,雙列集合可以通過key找到對(duì)應(yīng)的值僚碎。
有些朋友可能被SparseArray嚇到了猴娩,其實(shí)他就是HashMap<Integer,?>的改良版。想了解的朋友可以看一下這個(gè)鏈接http://www.cnblogs.com/RGogoing/p/5095168.html
5.Resource
官方是這樣介紹資源內(nèi)容的:
我們希望你能在你的表達(dá)式中使用資源引用內(nèi)容勺阐,因此你可以在你的表達(dá)式中使用資源和字符串格式化方法卷中。
其實(shí)這里也很簡單我們慢慢來看。
在表達(dá)式中引用資源↓
android:padding="@{large? (int)@dimen/largePadding : (int)@dimen/smallPadding}"
內(nèi)聯(lián)字符串格式:
android:text="@{@string/nameFormat(firstName, lastName)}"
同時(shí)渊抽,在string.xml文件中蟆豫,這些只是占位符,s是字符串懒闷,d是整數(shù)
<string name="nameFormat">Full Name: %1$s:%2$s</string>
<string name="nameFormatWithAge">Hello %1$s %2$s, %3$d ages</string>
內(nèi)聯(lián)復(fù)數(shù)格式:這個(gè)我是真沒用過十减,網(wǎng)上資料也少栈幸,不做解釋···
android:text="@{@plurals/orange(orangeCount, orangeCount)}"
<plurals name="orange">
<item quantity="one">Have an orange</item>
<item quantity="other">Have %d oranges</item>
</plurals>
6.Observable
這個(gè)我說不真切,對(duì)他也心存疑惑帮辟,還有貌似現(xiàn)在已經(jīng)支持雙向綁定了速址。等我會(huì)了再來寫····
7.ViewWithIds
這個(gè)之前已經(jīng)說過了,這里就不說了由驹。
android:id="@+id/firstName"===>binding.firstName.
8.ViewStub
ViewStub是Android布局優(yōu)化的一種方式芍锚,是一個(gè)非常輕量的View,他和View.Gone蔓榄,View.Visable類似,但又不一樣并炮,可以把它當(dāng)成一個(gè)占位符,只會(huì)被加載一次润樱,是一個(gè)非常不錯(cuò)的控件渣触。
在這里,他和上面講過的include在具體的實(shí)現(xiàn)上類似壹若,因?yàn)樗旧硪采侔粚硬季值摹?br>
但是奇怪的是
//這里標(biāo)紅嗅钻,不能自動(dòng)提示,雖然報(bào)錯(cuò)店展,但能運(yùn)行养篓,應(yīng)該是studio支持的不好
if (!mBinding.viewStub.isInflated()) {
mBinding.viewStub.getViewStub().inflate();}
9.Dynamic
重點(diǎn)來了。
RecyclerView + DataBinding.讓我們把之前學(xué)習(xí)的運(yùn)用過來赂蕴,最好先自己試著寫一下柳弄,再來看。
先說一下這個(gè)方法
setHasFixedSize(true);//我查了一下概说,貌似是說size固定的話碧注,使用此方法,效率會(huì)提升
我們重點(diǎn)看一下Adapter
public static class UserHolder extends RecyclerView.ViewHolder {
final UserItemBinding mBinding;
//通過構(gòu)造將View視圖和DataBinding進(jìn)行綁定
public UserHolder(View itemView) {
super(itemView);
mBinding = DataBindingUtil.bind(itemView);
}
//其實(shí)這個(gè)方法的本質(zhì)只是對(duì)外暴露UserItemBinding 用的
public void bind(@NonNull User user) {
mBinding.setUser(user);
}
}
在看一下這倆方法
@Override
//通過打氣筒獲取到item_view糖赔,同時(shí)傳遞給ViewHolder
public UserHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.user_item, viewGroup, false);
return new UserHolder(itemView);
}
@Override
//通過Binding對(duì)象將數(shù)據(jù)和視圖進(jìn)行綁定
public void onBindViewHolder(UserHolder holder, int position) {
holder.bind(mUsers.get(position));}
我去萍丐,這也太簡單太方便太簡單了!7诺洹逝变!
不過,平時(shí)我使用的都是陳宇明大神的https://github.com/CymChad/BaseRecyclerViewAdapterHelper
也是超級(jí)好用奋构,超級(jí)方便壳影。先學(xué)習(xí),以后會(huì)有更簡單的東西的··
10.Attribute setters
這個(gè)之前我們?cè)?.1的時(shí)候也說過弥臼,可能我說的不是很明白宴咧,這里有例子,我把作者的話引入過來径缅。
其實(shí)看這一塊的時(shí)候悠汽,我一直驚呼箱吕,我靠太牛逼了芥驳。柿冲。。怪我沒出息兆旬。
有了 Data Binding假抄,即使屬性沒有在 declare-styleable
中定義,我們也可以通過 xml 進(jìn)行賦值操作丽猬。 為了演示這個(gè)功能宿饱,我自定義了一個(gè) View ,屬性資源 [R.styleable.NameCard] 中只定義了一個(gè) age
屬性脚祟,其中 firstName 和lastName只有對(duì)應(yīng)的兩個(gè) setter方法谬以。只要有 setter方法就可以像下面代碼一樣賦值:
<com.liangfeizc.databindingsamples.attributesetters.UserView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/largePadding"
app:onClickListener="@{activity.clickListener}"
app:firstName="@{@string/firstName}"
app:lastName="@{@string/lastName}"
app:age="27"
/>
onClickListener
也是同樣道理,只不過我們是在 Activity 中定義了一個(gè) Listener
意思其實(shí)和我差不多由桌,我這個(gè)標(biāo)簽沒有這個(gè)屬性为黎,我可以自定義強(qiáng)塞給它這個(gè)屬性,當(dāng)它拿到屬性之后怎么去處理行您,一般的話會(huì)引入一個(gè)注解铭乾,比如我們這里的@BindingAdapter({"imageUrl", "error"})
這是什么意思類?一開始我也不理解娃循,后來看了11中的這個(gè)方法
@BindingAdapter("layout_height")
public static void setLayoutHeight(View view, float height) {
ViewGroup.LayoutParams params = view.getLayoutParams();
params.height = (int) height;
view.setLayoutParams(params);
}
那么意思再也明顯不過了炕檩,我得到的這個(gè)值應(yīng)該怎么去處理它。第一個(gè)參數(shù)對(duì)應(yīng)的是這個(gè)View控件捌斧,而第二個(gè)就是我們給他 賦的值
11.Conversions,終于要完了
不好意思笛质,這個(gè)我也沒看懂···
··綜上,也就辣么多了捞蚂。其實(shí)我唯一能告訴大家的就是妇押,DataBinding真的很簡單也很方便使用,你需要做的僅僅是看一遍demo洞难,不過最重要的還是千萬別急躁舆吮,啥事都有個(gè)循序漸進(jìn)的過程,尤其是學(xué)習(xí)队贱。加油色冀。