- 雙向綁定
- DataBinding剩下的注解
很快啊辕漂,就來到了DataBinding的第三篇。在這里將介紹DataBinding中高級的知識點(diǎn)(自認(rèn)為高級)通砍,下面就來瞧瞧這些高級的知識點(diǎn)。
1、雙向綁定
其實(shí)早該在介紹綁定表達(dá)式的時候應(yīng)該要介紹雙向綁定的了彻亲,但是為了雙向綁定完整,所以就留到了這吮廉,所謂雙向綁定是這樣的:
我們可以單向綁定數(shù)據(jù)和一些監(jiān)聽器(事件)苞尝。在更新數(shù)據(jù)的時候,綁定了的控件就會更新宦芦,而監(jiān)聽器發(fā)生改變的時候宙址,我們就更新綁定的數(shù)據(jù)。
這就是雙向綁定的原理调卑。
而DataBinding給我們提供了雙向綁定的基本實(shí)現(xiàn)以及自定義抡砂。
1.1、可觀察數(shù)據(jù)類型
并不是所有的數(shù)據(jù)類型都可以進(jìn)行雙向綁定恬涧,DataBinding給我們提供了一些:
大概是這么多注益。
而使用雙向綁定的表達(dá)式也和普通綁定表達(dá)式有那么一點(diǎn)點(diǎn)不一樣:
@={}
這就是雙向綁定表達(dá)式,比普通綁定表達(dá)式多了一個等號=
气破。
最常用到雙向表達(dá)式的莫過于EditText
控件了聊浅,當(dāng)輸入內(nèi)容時,更新綁定的數(shù)據(jù)现使,但改變數(shù)據(jù)時低匙,更新EditText
控件的顯示。
1.2碳锈、雙向綁定特性
也并不是所有的屬性都支持雙向綁定顽冶,至于哪些屬性(特性)可以進(jìn)行雙向綁定,官方也列出了一個表格:
1.3售碳、自定義可觀察數(shù)據(jù)類型(@Bindable)
如果DataBinding提供的可觀察數(shù)據(jù)類型都不能夠滿足你的業(yè)務(wù)强重,那么還是可以自定義的。
新建一個類贸人,繼承BaseObservable
间景,并創(chuàng)建一個屬性,給這個屬性加上@Bindable
注解艺智,然后重寫該屬性set
方法即可倘要,大概是這樣的:
class Demo : BaseObservable() {
@Bindable
var name: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.name)
}
}
@Bindable
注解:該注解主要作用于get方法或者是字段本身,作用是生成一個BR值供notifyPropertyChanged
方法調(diào)用以更新數(shù)據(jù)十拣。
這時我們就可以對name這個屬性進(jìn)行雙向綁定了:
<EditText
android:text=“@={demo.name}”/>
但是你實(shí)際運(yùn)行你會發(fā)現(xiàn)它報(bào)錯了封拧,報(bào)錯的原因是類型不匹配志鹃。這時候該怎么辦呢?
1.4泽西、雙向數(shù)據(jù)轉(zhuǎn)換(@InverseMethod)
Databinding提供了數(shù)據(jù)轉(zhuǎn)換的方案曹铃,單向和雙向都有,我們先來說雙向的捧杉。
定義一個靜態(tài)類陕见,提供兩個方法。一個充當(dāng)正向數(shù)據(jù)轉(zhuǎn)換器味抖,另外一個充當(dāng)反向數(shù)據(jù)轉(zhuǎn)換器淳玩,大概是這樣的:
object Canversion{
@InverseMethod("chToString")
fun stringToCh(value: String): CharSequence {
return value
}
fun chToString(value: CharSequence): String {
return value.toString()
}
}
事實(shí)上,兩個頂級函數(shù)也是可以的非竿。
InverseMethod
注解:該注解修飾的就是正向轉(zhuǎn)換器,而InverseMethod
接收一個參數(shù)谋竖,就是反向數(shù)據(jù)轉(zhuǎn)換器的名稱红柱。
還記得<import>
標(biāo)簽嗎,當(dāng)轉(zhuǎn)換器定義好之后蓖乘,我們就可以通過該標(biāo)簽將這個類導(dǎo)入到xml中锤悄,然后使用正向轉(zhuǎn)換器就可以了:
<import type=“…Conversion”/>
<EditText
android:text=“@={Conversion.stringToCh(demo.name)}”/>
1.5、自定義雙向綁定(InverseBindingAdapter)
如果DataBinding默認(rèn)實(shí)現(xiàn)的雙向綁定特性也不能滿足需求的時候嘉抒,就只能自定義了零聚。
事實(shí)上,雙向綁定就由兩個單向綁定(數(shù)據(jù)綁定和監(jiān)聽器綁定)組成的些侍,所以第一步就是建立兩個單向綁定隶症。下面重新實(shí)現(xiàn)android:text
的雙向綁定。
首先創(chuàng)建一個數(shù)據(jù)綁定:
@BindingAdapter("app:test")
fun test(view: TextView, text: CharSequence?) {
val oldText = view.text
if (text == oldText || (oldText.isNullOrEmpty())) {
return
}
if (text is Spanned) {
if (text == oldText) {
return; // No change in the spans, so don't set anything.
}
} else if (!haveContentsChanged(text, oldText)) {
return; // No content changes, so don't set anything.
}
view.text = text
}
在賦值之前需要對數(shù)據(jù)進(jìn)行判斷:
只有是更新的數(shù)據(jù)才可以被賦值岗宣。防止無限循環(huán)的發(fā)生蚂会。
然后,創(chuàng)建一個事件監(jiān)聽綁定:
@BindingAdapter("app:testAttrChanged")
fun setTextWatcher(view: TextView, textAttrChanged: InverseBindingListener?) {
val newValue: TextWatcher? = if (textAttrChanged == null) {
null
} else {
object : TextWatcher {
//code..
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
textAttrChanged.onChange()
}
//code..
}
}
if (newValue != null) {
view.addTextChangedListener(newValue)
}
}
這是一個事件監(jiān)聽耗式,當(dāng)EditText發(fā)生改變的時候胁住,就會通過InverseBindingListener
對象通知更改。
最后刊咳,將這兩個綁定關(guān)聯(lián)在一起:
@InverseBindingAdapter(attribute = "app:test", event = "app:testAttrChanged")
fun getTextString(view: TextView): CharSequence {
return view.text // 返回控件的值
}
InverseBindingAdapter
注解:該注解主要有兩個參數(shù)彪见,attribute
指定數(shù)據(jù)綁定的名稱,event
指定事件綁定的名稱娱挨。作用是將兩者結(jié)合起來形成雙向綁定余指,并且響應(yīng)事件綁定,在事件發(fā)生時返回控件的值让蕾。
通過這三步浪规,自定義雙向綁定的屬性就完成了:
<EditText
app:test=“@={demo.name}”/>
自定義雙向綁定的一個細(xì)節(jié):
在自定義雙向綁定中或听,對于app:testAttrChanged
是可以識別的,規(guī)律就是:
數(shù)據(jù)綁定名稱+AttrChanged笋婿。
所以在關(guān)聯(lián)的時候event
可以省略不寫誉裆。
1.6、簡化自定義雙向綁定(InverseBindingMethods和InverseBindingMethod)
有沒有更加簡單的方式實(shí)現(xiàn)雙向綁定呢缸濒?答案是沒有的W愣!雙向綁定就必須是一個數(shù)據(jù)綁定加上一個事件綁定庇配。這是永遠(yuǎn)都沒辦法省略的斩跌。但是如果你有多個雙向綁定需要實(shí)現(xiàn),那么可以簡化的只有InverseBindingAdapter
注解修飾的方法了捞慌。
首先定義一個類:
@InverseBindingMethods(
InverseBindingMethod(
type = TextView::class,
attribute = "app:test",
method = "getText"
)
)
object BindingAdapterImpl
InverseBindingMethods
:該注解接收的參數(shù)是InverseBindingMethod
數(shù)組耀鸦。
而一個InverseBindingMethod
對應(yīng)的就是一個InverseBindingAdapter
,下面我們來分析一下InverseBindingMethod
也就是說InverseBindingMethods
和InverseBindingMethod
的作用就是批量的InverseBindingAdapter
啸澡。
InverseBindingMethod
該注解有四個參數(shù):
type
:是一個class對象袖订,指定雙向綁定的控件,比如TextView
attribute
:和InverseBindingAdapter
中同名的參數(shù)作用一樣嗅虏,指定數(shù)據(jù)綁定的方法洛姑。
event
:和InverseBindingAdapter
中同名的參數(shù)作用一樣,指定事件綁定的方法皮服。(可以看出楞艾,上面的例子我沒有寫該屬性,是因?yàn)榭梢宰詣油茰y)
method
:指定控件提供數(shù)據(jù)的方法龄广。(事實(shí)上該參數(shù)也可以不寫硫眯,當(dāng)控件存在與attribute
同名的get方法時,也就是說如果TextView中存在一個getTest
方法蜀细,那么這個參數(shù)就可以缺手弁)
需要注意的是:這兩個注解替代的是InverseBindingAdapter
,所以數(shù)據(jù)綁定和事件綁定依舊需要實(shí)現(xiàn)奠衔。
一句話概括:
當(dāng)可觀察數(shù)據(jù)對象更改時谆刨,通過attribute
指定的方法更新type
的對象,當(dāng)event
事件發(fā)生時归斤,將從method
方法中獲得數(shù)據(jù)返回給可觀察數(shù)據(jù)對象痊夭。
2、DataBinding剩下的注解
終于說完雙向綁定了脏里,在說明雙向綁定的時候也將和雙向綁定有關(guān)的注解說了一下她我,接下來就說說DataBinding剩下的注解。
2.1、單向數(shù)據(jù)轉(zhuǎn)換(BindingConversion)
上面提到數(shù)據(jù)轉(zhuǎn)換有兩種番舆,雙向的已經(jīng)介紹了酝碳,現(xiàn)在來看單向的數(shù)據(jù)轉(zhuǎn)換:
@BindingConversion
fun dateToString(time: Date): String{
return SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(time)
}
將Date類型轉(zhuǎn)換成String類型輸出。
<TextView
android:text=“@{date}”/>//date是一個Date類型的對象
注意:
單向數(shù)據(jù)轉(zhuǎn)換只需要輸入(參數(shù)列表)輸出(返回值)對上即可自動使用恨狈,無需手動調(diào)用疏哗。
再次注意:所有的數(shù)據(jù)轉(zhuǎn)換都只能一對一。
2.2禾怠、簡化單向綁定(BindingMethods和BindingMethod)
@BindingMethods({
@BindingMethod(type = TextView.class, attribute = "android:autoLink", method = "setAutoLinkMask")
})
和雙向綁定的差不多返奉,BindingMethods
接收的也是BindingMethod
的數(shù)組。
來看看BindingMethod
注解:
@BindingMethod
注解有三個變量:
type
:指定單向綁定的控件吗氏,比如:TextView
attribute
:指定單向綁定的名稱
method
:指定響應(yīng)單向綁定的set方法
BindingMethods
和BindingMethod
相當(dāng)于批量的BindingAdapter
芽偏。
一句話概括:
attribute
屬性實(shí)現(xiàn)單向綁定,通過method
方法將值設(shè)置給type
類型的控件弦讽。
總結(jié)
最后一篇介紹了dataBinding的雙向綁定和剩下的注解污尉,到此Databinding算是基本講完了。DataBinding主要分為三部分:xml部分往产,activity/fragment部分以及自定義綁定(單向綁定和雙向綁定)部分十厢。
到后面你會發(fā)現(xiàn),xml之所以可以使用綁定表達(dá)式捂齐,是因?yàn)锧BindingAdapter標(biāo)簽。當(dāng)然了缩抡,這只是DataBinding的使用奠宜,真正的實(shí)現(xiàn):為什么@BindingAdapter這么神奇,其背后的原理才是DataBinding真正的核心瞻想。這就是注解部分的內(nèi)容了压真。對于日常開發(fā)來說,學(xué)完DataBinding的這幾個注解就已經(jīng)足夠了蘑险。
對于學(xué)習(xí)滴肿,最重要的是要去寫,只有真正寫過佃迄,實(shí)現(xiàn)了泼差,才能算掌握了。
因?yàn)檎胬矶际窃趯?shí)踐當(dāng)中呵俏。