【版權申明】非商業目的註明出處可自由轉載
博文地址:https://blog.csdn.net/ShuSheng0007/article/details/106267286
出自:shusheng007
概述
DataBinding 最早應該是在2015年末的時候就被提出了,那我爲什麼現在才寫一些相關的文章呢?因爲我不喜歡也不看好這項技術!那爲什麼又要寫呢?因爲目前公司的項目中在用,無論我喜不喜歡都需要使用,我的吃飯啊!
我是不會在自己可以主導的項目中主動使用此技術的,那爲什麼我這麼討厭它呢?
主要是因爲我認爲其會給項目維護帶來糟糕的體驗。DataBinding使的程序員可以在layout文件中寫代碼了,也就是可以將業務邏輯混合在視圖文件中了,這不僅降低了layout文件的重用性,還使View與業務邏輯一定程度綁定了。雖然Google一直在強調,不要再layout文件中使用複雜的表達式,但是你要知道給同一個項目提交代碼的不僅有經驗豐富的王二狗,也會有實習生牛翠花,還可能有外包林蛋大,code review 在很多公司根本沒有或者就是一個擺設。
但是你也不用太擔心,雖然我不喜歡它但是不妨礙喜歡它的你學習此項技術。我準備以3篇文章總結一下這個庫的一些知識
- 使用入門
- Binding Adatper,雙向綁定等
- 與LiveData 等架構組件配合,以及原理等
DataBinding 總覽
我們知道,Android的UI一般是使用 xml 格式的layout
文件表示的, 要想爲UI上的view賦值,首先需要在代碼中獲取到相應的view,即 findViewById。
最開始那一幫寫Android的也沒覺得有什麼不好,大家都這麼用,世界一片和諧。但是突然有些不安分的程序員(例如JakeWharton)不幹了:這太TM繁瑣了,能不能有更好的辦法呢, 於是參考其他程序員的想法寫出了 ButterKnife 。就這樣又過了兩年,隨着Android生態的壯大與穩定,Google Android 團隊終於有時間開始搞事情了,於是Jetpack橫空出世。DataBinding也被收歸其旗下了,是其中解決View綁定的庫,但是感覺一下用力過猛,弄成DataBinding了,最近又出了ViewBinding,也許是一個糾正吧。我認爲ViewBinding纔是解決這個問題的希望,強烈建議閱讀文章 秒懂Android開發之ViewBinding,一代神器ButterKnife的終結者
本文包含如下內容:
- DataBinding 簡單介紹
- DataBinding 試圖解決的問題及其使用場景
- DataBinding 的入門使用
簡介
Data Binding 類庫是 Android Jetpack 的一部分,通過它你可以將數據與UI元素的綁定工作(就是互相賦值)在layout 文件中以聲明的方式完成,而不是在viewControlor,例如Activity,Fragment 中。
例如我們要給一個Textview賦值,傳統方式代碼如下:
findViewById<TextView>(R.id.user_namet).apply {
text = viewModel.userName
}
而使用data binding後就可以將賦值的邏輯放到layout文件中了。
<TextView
...
android:text="@{viewmodel.userName}" />
整體來說呢就這麼點東西,但是鋪開了還是有些看頭的,所以小夥伴們搬好小板凳,準備開講。
解決的問題及其使用場景
解決的問題主要有兩點:
- 省去程序員自己調用
findViewById
獲取UI元素,使用程序生成 - 數據與UI相互賦值問題,包括事件
data binding的精髓應該在第二點上,如果你僅僅是想去掉煩人的findViewById
,那麼Google新推出的 ViewBinding 更加適合,因爲其簡單而高效。
實戰使用
紙上得來終覺淺,絕知此事要躬行。看半天如果自己不動手寫一下,那都是一團漿糊,等到用的時候還是不會,讓我們一起coding起來
前提:Android Studio 4.0
我們準備開發如下圖所示的一個頁面,通過下面兩個按鈕動態修改紅框中的文字
- 打開data binding 功能
在要使用data binding 的Module 的gradle 文件中如下配置即可
android{
...
buildFeatures {
dataBinding = true
}
}
如果使用Kotlin 請記得使用 kotlin-kapt
插件
apply plugin: 'kotlin-kapt'
注意:如果你的項目引用了一個使用了data binding的類庫,那麼你就被綁架了,你也必須開啓data binding,所以如果你在寫一個類庫,請慎重使用此技術。
- 將你的layout文件改成data binding 要求的格式
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data >
...
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".databinding.DataBindingActivity">
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
最外層必須是<layout>
標籤,那個<data>
標籤裏面存放要在layout中引用的數據。那個ConstraintLayout 纔是我們需要的UI.
值得說明的是,AndroidStudio支持將普通的layout轉換爲dataBinding需要的layout格式。
在需要轉換的layout文件中外層View右鍵,選擇Context Actions,然後選擇轉換爲data binding layout 即可。如下圖所示
-
與ViewControlor綁定
即讓我們的Activity等視圖控制器與data binding 生成的類綁定,如下所示
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityDataBindingBinding =
DataBindingUtil.setContentView(this, R.layout.activity_data_binding)
}
這裏使用了DataBindingUtil
來進行綁定,除此之外,那個layout文件的生成類ActivityDataBindingBinding
裏還有幾個靜態inflate(...)
方法可以用於綁定.
- 在layout文件中書寫表達式
當完成以上3步後就可以在layout文件裏面寫表達式了。
首先在<data>
標籤裏面聲明聲明變量,聲明好了就可以在表達式中引用了,例如本例中聲明瞭viewModel作爲變量。
<data >
<variable
name="viewModel"
type="top.ss007.androiddevmemo.databinding.DataBindingViewModel" />
</data>
第二在view中書寫表達式,在表達式中就可以引用我們聲明的變量了,例如我的ViewMode文件如下
class DataBindingViewModel : ViewModel() {
var action: String = "邀請牛翠花晚上一起生猴子"
var targetGirl: Girl = Girl("牛翠花",30)
fun seduceGirl(girl: Girl) {
targetGirl = Girl("上官無雪", 18)
action = "邀請${girl.age.toString() + "的" + girl.name}晚上一起看月亮"
}
fun bornSon(girl: Girl) {
targetGirl = Girl("牛翠花", 30)
action = "邀請${girl.age.toString() + "的" + girl.name}晚上一起生猴子"
}
}
其中Girl 是一個普通的data class
我就可以使用其中的變量和方法了
爲TextView 賦值
<TextView
android:id="@+id/tv_action"
...
android:text="@{viewModel.action}"/>
爲Button設置點擊事件
<Button
android:id="@+id/btn_born_son"
...
android:onClick="@{(view)->viewModel.bornSon(viewModel.targetGirl)}"
/>
那到此是不是就已經好了呢?非常可惜,還差最後一步,因爲你想想,你在layout中聲明瞭viewModel變量,但是我們沒有爲其賦值啊,那他肯定是個null,所以視圖中自然也獲取不到值。
值得說明的是,其不會崩潰,因爲dataBinding做了處理,這點還是比較讚的。
- 給layout文件中聲明的變量賦值
override fun onCreate(savedInstanceState: Bundle?) { ... val viewModel = ViewModelProvider(this).get(DataBindingViewModel::class.java) binding.viewModel = viewModel }
完成以上5步後就大功告成了,感覺自己好牛逼。但是當你滿心歡喜的去點擊下面的按鈕時,UI盡然沒有任何反應! 納尼?what happened? 什麼情況?穩住,我們能懂。。。
綁定可觀察數據(observable data)
我們在點擊按鈕時更新了數據,但是發現UI並沒有更新,這不是我們想要的啊。那是因爲我們的數據是普通的數據,要想當數據改變時通知UI,需要此數據爲observable data。
可觀察數據分爲三類
- Objects
實現了androidx.databinding.Observable
接口的類,google給很貼心的幫我們實現了一個BaseObservable
, 我們一般都是繼承這個類, 負責在屬性值改變時通知data binding一下。
方法爲:用@Bindable
標記getter, 同時在setter裏調用notifyPropertyChanged
方法 即可。
例如本例代碼如下
class Girl : BaseObservable() {
@get:Bindable
var name: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.name)
}
@get:Bindable
var age: Int = 18
set(value) {
field = value
notifyPropertyChanged(BR.age)
}
}
- Fields
dataBinding 類庫提供的封裝 ObservableField<T>
,例如要使一個String變量可以觀察可如下定義:
val action: ObservableField<String> = ObservableField("邀請牛翠花晚上一起生猴子")
其還爲int, boolean, long 等基礎類型提供了相應的實現,相比ObservableField
其在進行訪問操作時不進行裝箱和拆箱,效率有所提高。
ObservableBoolean
ObservableByte
ObservableChar
ObservableShort
ObservableInt
ObservableLong
ObservableFloat
ObservableDouble
ObservableParcelable
- Collections
ObservableArrayMap
與ObservableArrayList
運行結果
當把我們的數據修改爲可Observable data後再次運行,點擊按鈕時,UI也會隨之改變。
總結
至此,相信你已經可以非常自信的上手DataBinding了,你今天又不用加班了,開心哇??
在文中我沒有過多的提及layout
中表達式的語法,一是因爲本文目的是讓你快速上手,二是因爲我認爲這個在你使用遇到困難時查官方文檔纔是正解。
下一篇讓我們一起看一下 Binding Adapter 以及雙向綁定。
如果你覺得對你有用,請反手給我一個贊,如果你還想隨時找到我,請猛戳關注按鈕。
望你保重身體,享受編碼,享受生活。
本文源碼下載地址:AndroidDevMemo
官方教程:Data Binding Library