Android Jetpack - DataBinding

什么是 DataBinding ?

DataBinding 是屬于 Jetpack 的一個(gè)支持庫(kù)恬偷,可以讓你以在布局中聲明屬性的方式替代編碼方式將布局中的 UI 組件和應(yīng)用數(shù)據(jù)進(jìn)行綁定

通常我們讓控件和數(shù)據(jù)交互的方式如下面的代碼,調(diào)用 findViewById() 獲取 TextView 控件并將 viewModel 中的 userName 屬性賦值給它:

findViewById<TextView>(R.id.textView).apply {
    text = viewModel.userName
}

用 DataBinding 的方式就能消除上面所必須的代碼,如下所示丛晦,效果和上面的代碼完全相等账嚎,但是簡(jiǎn)潔多了愁溜,注意表達(dá)式被包含在 @{}

<TextView
    android:text="@{viewmodel.userName}" />

這樣你就不用在 Activity 中調(diào)用 UI 框架去綁定組件再賦值了罐栈,優(yōu)點(diǎn)是更簡(jiǎn)潔易維護(hù)(Jetpack 其它組件都完美支持 DataBinding)咕缎,而且也減少了內(nèi)存泄露和空指針的風(fēng)險(xiǎn)

如何使用 DataBinding 庫(kù) ?

1料扰、創(chuàng)建一個(gè)新項(xiàng)目

2凭豪、啟用 DataBinding 并轉(zhuǎn)換布局

build.gradle

android {
...
    dataBinding {
       enabled true
    }
}

轉(zhuǎn)換布局(?+?)

image.png

轉(zhuǎn)換完成之后代碼大概是這樣的

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>

    </data>
    <android.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MainActivity">
            ...

<data> 標(biāo)簽就是我們放布局變量的地方,布局變量用于編寫布局表達(dá)式晒杈,布局表達(dá)式被放置在元素的屬性值中嫂伞,格式是@{布局表達(dá)式}

3、實(shí)現(xiàn)你的第一個(gè)布局表達(dá)式

<data> 標(biāo)簽中添加一個(gè) String 類型的布局變量

<data>
    <variable name="name" type="String"/>
</data>

在 TextView 控件的屬性中使用此變量拯钻,注意 id 和 variable name 盡量不要沖突

<TextView
        android:id="@+id/textView"
        android:text="@{name}"
        ...

此時(shí)帖努,@{name} 就是一個(gè)簡(jiǎn)單的引用布局變量的布局表達(dá)式了

4、修改 Activity 中的代碼調(diào)用

修改

setContentView(R.layout.activity_main)

val binding : ActivityMainBinding =
    DataBindingUtil.setContentView(this,R.layout.activity_main)

現(xiàn)在粪般,直接為 binding 的屬性賦值即可

binding.name = "Kim John"

運(yùn)行 app 看看效果

5然磷、處理用戶事件

至此,基礎(chǔ)的數(shù)據(jù)展示部分已經(jīng)完成刊驴,但 DataBinding 的強(qiáng)大遠(yuǎn)不止于此,它還可以處理用戶事件以及布局表達(dá)式的調(diào)用寡润,我們創(chuàng)建一個(gè) viewModel 以便演示其功能

MainViewModel

class MainViewModel : ViewModel(){
    private val _name = MutableLiveData("Kim John")
    val name: LiveData<String> = _name
}

修改布局文件

<data>
    <!--<variable name="name" type="String"/>-->
    <variable name="viewModel" type="com.skyrin.jetpack_databanding.MainViewModel"/>
</data>

...

<TextView
        android:id="@+id/textView"
        android:text="@{viewModel.name}"
        ...

修改 MainActivity

class MainActivity : AppCompatActivity() {
    // 懶加載得到 viewModel 對(duì)象
    private val viewModel by lazy {
        ViewModelProviders.of(this).get(MainViewModel::class.java)
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding : ActivityMainBinding =
            DataBindingUtil.setContentView(this,R.layout.activity_main)
        binding.viewModel = viewModel
    }
}

運(yùn)行 app 看看效果

DataBinding 還可以和 LiveData 完美結(jié)合捆憎,我們可以看到 MainViewModel 中的 name 變量是 LiveData 類型,讓我們更進(jìn)一步梭纹,為 binding 添加 LifecycleOwner 讓它具備數(shù)據(jù)感知能力

override fun onCreate(savedInstanceState: Bundle?) {

    ...
    
    binding.lifecycleOwner = this
}

為了更好的展示 DataBinding 與 LiveData 的互動(dòng)躲惰,我們?cè)?MainViewModel 增加 likes 屬性

class MainViewModel : ViewModel() {
    private val _name = MutableLiveData("Kim John")
    private val _likes = MutableLiveData(0)
    val name: LiveData<String> = _name
    val likes: LiveData<Int> = _likes
    
    fun onLike() {
        _likes.value = (likes.value ?: 0) + 1
    }
}

然后修改布局變量和表達(dá)式如下

<androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    <TextView
            android:id="@+id/tv_name"
            android:text="@{viewModel.name}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="200dp"/>
    <ProgressBar
            android:id="@+id/pb_likes"
            android:max="@{10}"
            android:progress="@{viewModel.likes}"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="200dp"
            android:layout_height="10dp"
            app:layout_constraintStart_toStartOf="@+id/tv_name" app:layout_constraintEnd_toEndOf="@+id/tv_name"
            android:layout_marginTop="32dp" app:layout_constraintTop_toBottomOf="@+id/tv_name"/>
    <Button
            android:id="@+id/btn_like"
            android:text="@{Integer.toString(viewModel.likes)}"
            android:onClick="@{()->viewModel.onLike()}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="@+id/pb_likes"
            app:layout_constraintEnd_toEndOf="@+id/pb_likes" android:layout_marginTop="32dp"
            app:layout_constraintTop_toBottomOf="@+id/pb_likes"
    />
</androidx.constraintlayout.widget.ConstraintLayout>

運(yùn)行 app 并點(diǎn)擊 button,你會(huì)看到 progress 進(jìn)度隨著點(diǎn)擊次數(shù)增加变抽,而我們并沒(méi)有在 MainActivity 增加任何代碼础拨,這一切都由 DataBinding 與 LiveData 配合完成

image.png

6、BindingAdapter

@BindingAdapter 是 DataBinding 中非常有用的一個(gè)注解绍载,此外還有 @BindingConversion诡宗、@BindingMethods 等,這里介紹一下最常用的 BindingAdapter

我們先在 MainViewModel 中添加 popularity 屬性击儡,并和 likes 建立關(guān)聯(lián)

class MainViewModel : ViewModel() {

    ...
    
    // 聲明 popularity 并通過(guò) Transformations 創(chuàng)建其與 likes 的關(guān)系
    val popularity: LiveData<Popularity> = Transformations.map(_likes) {
        when {
            it > 9 -> Popularity.STAR
            it > 5 -> Popularity.POPULAR
            else -> Popularity.NORMAL
        }
    }
}
enum class Popularity {
    NORMAL, // 普通
    POPULAR, // 受歡迎
    STAR // 巨星
}

創(chuàng)建 BindingAdapter.kt塔沃,用于創(chuàng)建屬性并提供自定義算法

@BindingAdapter("app:popularityColor")
fun popularityColor(view: TextView, popularity: Popularity) {
    val color = getColorPopularity(view.context,popularity)
    view.setTextColor(color)
}
@BindingAdapter("app:popularityText")
fun popularityText(view: TextView, popularity: Popularity) {
    view.text = getTextPopularity(popularity)
}
fun getTextPopularity(popularity: Popularity): String? {
    return when (popularity) {
        Popularity.NORMAL -> "??"
        Popularity.POPULAR -> "??"
        Popularity.STAR -> "??"
    }
}
fun getColorPopularity(context: Context, popularity: Popularity): Int {
    return when (popularity) {
        Popularity.NORMAL -> ContextCompat.getColor(context, R.color.normal)
        Popularity.POPULAR -> ContextCompat.getColor(context, R.color.popular)
        Popularity.STAR -> ContextCompat.getColor(context, R.color.star)
    }
}

現(xiàn)在,我們可以直接在布局屬性中使用它們

<androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    <TextView
            android:id="@+id/tv_name"
            android:text="@{viewModel.name}"
            app:popularityColor="@{viewModel.popularity}"
            ...
            />
    
    ...
    
    <TextView
            android:id="@+id/tv_popularity"
            app:popularityText="@{viewModel.popularity}"
            ...
            />
</androidx.constraintlayout.widget.ConstraintLayout>

運(yùn)行 app阳谍,查看我們新加入的功能

demo.gif

完整示例代碼

https://github.com/realskyrin/jetpack_databanding

總結(jié)

至此蛀柴,你應(yīng)該已經(jīng)了解到 DataBinding 的強(qiáng)大之處了,雖然只是一個(gè)簡(jiǎn)單的可交互界面矫夯,但如果用傳統(tǒng)方式去實(shí)現(xiàn)的話 Activity 中至少有 100 行以上代碼鸽疾,而 DataBinding 讓 Activity 變得十分清爽,此外训貌,DataBinding 與 LiveData制肮、ViewModel 等 Jetpack 組件也是天作之合,Android 官方也非常推薦使用 Jetpack 來(lái)開發(fā) APP,這已經(jīng)形成 Android 開發(fā)的固定套路了弄企,熟練掌握這些套路能讓你多一些時(shí)間享受生活超燃,后續(xù)我會(huì)繼續(xù)更新其它 Jetpack 組件的用法,如果覺(jué)得文章還行的話來(lái)個(gè)素質(zhì)三連吧??

參考

https://developer.android.google.cn/topic/libraries/data-binding/?hl=en
https://codelabs.developers.google.com/codelabs/android-databinding/

Jetpack 系列文章

Android Jetpack - Lifecycles

Android Jetpack - ViewModel

Android Jetpack - DataBinding

Android Jetpack - Room

Android Jetpack - LiveData

Android Jetpack - WorkManager(待更)

Android Jetpack - Paging(待更)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拘领,一起剝皮案震驚了整個(gè)濱河市意乓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌约素,老刑警劉巖届良,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異圣猎,居然都是意外死亡士葫,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門送悔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)慢显,“玉大人,你說(shuō)我怎么就攤上這事欠啤〖栽澹” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵洁段,是天一觀的道長(zhǎng)应狱。 經(jīng)常有香客問(wèn)我,道長(zhǎng)祠丝,這世上最難降的妖魔是什么疾呻? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮写半,結(jié)果婚禮上岸蜗,老公的妹妹穿的比我還像新娘。我一直安慰自己叠蝇,他們只是感情好散吵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蟆肆,像睡著了一般矾睦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上炎功,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天枚冗,我揣著相機(jī)與錄音,去河邊找鬼蛇损。 笑死赁温,一個(gè)胖子當(dāng)著我的面吹牛坛怪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播股囊,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼袜匿,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了稚疹?” 一聲冷哼從身側(cè)響起居灯,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎内狗,沒(méi)想到半個(gè)月后怪嫌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柳沙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年岩灭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赂鲤。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡噪径,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出数初,到底是詐尸還是另有隱情找爱,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布妙真,位于F島的核電站,受9級(jí)特大地震影響荚守,放射性物質(zhì)發(fā)生泄漏珍德。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一矗漾、第九天 我趴在偏房一處隱蔽的房頂上張望锈候。 院中可真熱鬧,春花似錦敞贡、人聲如沸泵琳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)获列。三九已至,卻和暖如春蛔垢,著一層夾襖步出監(jiān)牢的瞬間击孩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工鹏漆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留巩梢,地道東北人创泄。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像括蝠,于是被迫代替她去往敵國(guó)和親鞠抑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354