Jetpack 之 DataBinding使用

DataBinding:数据绑定,即布局中的控件与可观察的数据进行绑定。


DataBinding并非是将UI逻辑搬到XML中写导致而难以调试 ,只负责绑定数据,UI控件与其需要的终态数据进行绑定。 终态数据是指UI控件直接需要的数据(UI数据),string值、int值等,而不是一段逻辑(不然就叫 LogicBinding了 ,虽然DataBinding支持逻辑表达式)。

明确了 DataBinding 的 职责边界后 应该知道了:原本的逻辑代码 该怎么写还是怎么写,只不过不再需要 textView.setText(user.name),而是直接 user.setName()。

所以 DataBinding 的本质就是 “终态数据” 与 “UI控件” 的绑定,具有以下优势:

  • 无需多处调用控件,原本调用的地方只需要set数据即可
  • 第一点的延伸,无需手动判空
  • 第一点的延伸,完全不用写模板代码 findViewById
  • 并且,引入DataBinding后,原本的 UI 逻辑无需改动,只需设置终态数据

逻辑放入xml中的写法,是不建议的。数据值应 直接反映UI控件需要的结果,而不是作为逻辑条件放在 xml 中。所以,DataBinding 不负责 UI 逻辑,逻辑原本在哪里写,现在还是在哪里写,只不过,原本调用控件实例去刷新状态的方式,现在改成了数据驱动。 这就是DataBinding 的核心目标。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#layout
<?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">

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

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:text="@{user}"
android:id="@+id/t1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="click to add user"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/t1" />

<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="click to delete user"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button1" />

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#TestDataBindingActivity.kt
class TestDataBindingActivity : AppCompatActivity() {
private val userModel: UserListViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityDatabindingBinding = DataBindingUtil.setContentView(this, R.layout.activity_databinding)

userModel.getUserLiveData().observe(this, {
var s = ""
for (item in it) { s = s + item.name + " / " + item.age + "\n" }
binding.user = s
})

userModel.getLoadingLiveData().observe(this, {
findViewById<ProgressBar>(R.id.progressBar).visibility = if (it) View.VISIBLE else View.GONE
})

userModel.getUserData()
binding.button1.setOnClickListener { userModel.addUserData() }
binding.button2.setOnClickListener { userModel.deleteUserData() }
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#UserListViewModel.kt
class UserListViewModel : ViewModel() {

private val userList: MutableLiveData<MutableList<User>> by lazy {
MutableLiveData<MutableList<User>>()
}

private val isLoading: MutableLiveData<Boolean> by lazy {
MutableLiveData<Boolean>()
}

fun getUserLiveData(): LiveData<MutableList<User>> {
return userList
}

fun getLoadingLiveData(): LiveData<Boolean> {
return isLoading
}

fun addUserData() {
val tmp = userList.value
tmp?.add(User("bob", "99"))
userList.value = tmp
}

fun deleteUserData() {
val tmp = userList.value
tmp?.removeAt(0)
userList.value = tmp
}

fun getUserData() {
isLoading.value = true
UserRepository.get().getUserFromServer(object : DataCallBack<MutableList<User>> {
override fun onSuccess(data: MutableList<User>) {
userList.postValue(data)
isLoading.postValue(false)
}

override fun onFailed() {
isLoading.postValue(false)
}
})
}
}

参考文章:
https://juejin.cn/post/6923859213403979789
https://github.com/stewForAni/Kotlin-Jetpack