Data binding 強化了 XML 在 project 裡的功能和地位,讓元件可以在 XML 就綁上點擊事件、資料等等。
在開始進行 data binding 以前,要先設定環境。
首先是在 Gradle(Module:app)加上以下
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
buildFeatures {
dataBinding true
}
}
dependencies {
kapt "com.android.databinding:compiler:3.1.4"
}
跟 Gradle(Project: ProjectName)
buildscript {
ext.kotlin_version = "1.4.10"
dependencies {
classpath "com.android.tools.build:gradle:4.0.2"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
在 data binding 時,會跟 view model 有比較大的關連,所以先講 view model。
這次我的資料只有放在 view model 裡面了。
class MainViewModel: ViewModel(){
var data= ObservableField<String>("")
init {
data.set("init")
}
fun btnClick(){
data.set("clicked!")
}
}
裡面有一個資料跟方法
Observable 是給 view model 用的型態,跟之前講的 live data 有點類似,可以用 getter and setter 取值給值。
一個 text view 一個 edit view 一個 button
data binding 要在最外面加上 layout 包起來,記得把 xmlns 的屬性也移進去。
<?xml version="1.0" encoding="utf-8"?>
<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>
<variable
name="viewModel"
type="com.example.mvvm.ui.main.MainViewModel"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.MainActivity">
<TextView
android:id="@+id/textMainResult"
android:text="@{viewModel.data}"
android:textSize="30sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/editMain"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<EditText
android:id="@+id/editMain"
android:gravity="center"
android:text="@={viewModel.data}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.3" />
<Button
android:id="@+id/btnMainResult"
android:text="result"
android:onClick="@{() -> viewModel.btnClick()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/editMain"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.2"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
可以發現除了外面的 layout 以外,跟一般的 XML 前面還多了 data 的標籤。那是 XML 的資料來源,通常會丟 view model 近來,這樣就可以把 view model 裡的東西丟給各元件了。
從 text view 的 text 屬性可以看到,他是利用"@{viewmodel.你要的ObservableField成員}"
進行 data binding。
如果想要可以改變 binding 的值,要在 @ 跟 { } 之間加上等號,這樣就代表可以雙向改變此資料,例如 edit text,在打入字的時候,data 也會跟著改變。
按鈕則可以在 onClick 屬性加上方法,套用上 "@{() -> 你要的方法}"
。
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by lazy {
ViewModelProvider(this, MyViewModelFactory()).get(MainViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
// binding.viewModel 是 XML <data> 裡的那個
binding.viewModel = viewModel
}
}
個人覺得 data binding 最舒服的地方就是 activity 不用再加上一大堆的 findViewById。
只要加上 binding 跟 設置 viewModel。
中間的 ActivityMainBinding 不是我宣告的,做好以後 build 成功會自動出現。
打入 edit text
按下按鈕
在最後寫個筆者認為的 data binding 的缺點,就是不方便 debug。
每次有地方寫錯,它只會跟你說 ActivityMainBindingImpl 出錯誤了,留下一模一樣的東西,實在是有點難搞。
筆者之後就都還是做成 LiveData 了 :|