DataBinding學(xué)習(xí)使用進(jìn)階之路

最近在學(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í)队贱。加油色冀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市柱嫌,隨后出現(xiàn)的幾起案子锋恬,更是在濱河造成了極大的恐慌,老刑警劉巖编丘,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件与学,死亡現(xiàn)場(chǎng)離奇詭異彤悔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)索守,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門晕窑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人卵佛,你說我怎么就攤上這事杨赤。” “怎么了截汪?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵疾牲,是天一觀的道長。 經(jīng)常有香客問我衙解,道長阳柔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任蚓峦,我火速辦了婚禮舌剂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘枫匾。我一直安慰自己架诞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布干茉。 她就那樣靜靜地躺著谴忧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪角虫。 梳的紋絲不亂的頭發(fā)上沾谓,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音戳鹅,去河邊找鬼均驶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛枫虏,可吹牛的內(nèi)容都是我干的妇穴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼隶债,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼腾它!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起死讹,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤瞒滴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后赞警,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妓忍,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡虏两,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了世剖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片定罢。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖搁廓,靈堂內(nèi)的尸體忽然破棺而出引颈,到底是詐尸還是另有隱情,我是刑警寧澤境蜕,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站凌停,受9級(jí)特大地震影響粱年,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜罚拟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一台诗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赐俗,春花似錦拉队、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至叔扼,卻和暖如春事哭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓜富。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工鳍咱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人与柑。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓谤辜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親价捧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子丑念,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容