Android DataBinding学习(二):数据更新
一.单向绑定
上一篇文章Android DataBinding学习(一) kotlin版本介绍了DataBinding的基础用法,但是上篇文章最后提到一个问题,就是"如何更新UI",对于这个问题,我们可以用"单向绑定"技术来解决。
1.BaseObservable
为了能够实现单向绑定,测试代码的实现是一个带SeekBar的UI,后台用线程不断更新SeekBar的数据。XML代码:
<?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>
<import type="com.work.binding.practice.data.ProgressData" />
<variable
name="progressData"
type="ProgressData" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatSeekBar
android:id="@+id/first_seek_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:max="100"
android:progress="@{progressData.progress}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/start"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:onClick="startThread"
android:background="@color/colorAccent"
android:text="启动线程"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/first_seek_bar" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
数据类:ProgressData
class ProgressData: BaseObservable(){
@Bindable
var progress:Int?=0
set(value) {
field = value
notifyPropertyChanged(BR.progress)
}
}
注意到这里有时候@Bindable 会报错To use data binding annotations in Kotlin, apply the 'kotlin-kapt' plugin in your module's build.gradle ,解决办法需要在当前项目的build.gradle脚本中增加插件apply plugin: 'kotlin-kapt' 。 编译通过之后,到这里就已经完成了单向绑定了。
Activity界面代码:
class SeekBarActivity:AppCompatActivity() {
val binding:ActivitySeekBarBinding by lazy {
DataBindingUtil.setContentView(this, R.layout.activity_seek_bar)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding.progressData = ProgressData()
}
fun startThread(view: View){
val updateThread = Thread {
while (true){
if(binding.progressData?.progress?:Int.MAX_VALUE >= 100){
return@Thread
}
binding.progressData?.progress = binding.progressData?.progress?.inc()
Thread.sleep(1000)
}
}
updateThread.start()
}
}
2.ObservableXXX类
除了上面提到的BaseObservable方法还可以考虑使用ObservableXXX类,比如ObservableInt,ObservableField,ObservableFloat等类,同样可以实现单向绑定。代码如下:
数据类:ProgressData
class ProgressData{
var progress:ObservableInt = ObservableInt(0)
}
Activity稍微修改下:
class SeekBarActivity:AppCompatActivity() {
val binding:ActivitySeekBarBinding by lazy {
DataBindingUtil.setContentView(this, R.layout.activity_seek_bar)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding.progressData = ProgressData()
}
fun startThread(view: View){
val updateThread = Thread {
while (true){
binding.progressData?.progress?.let {
if (it.get() >= 100){
return@Thread
}
it.set(it.get().inc())
}?:return@Thread
Thread.sleep(1000)
}
}
updateThread.start()
}
}
二.双向绑定
既然可以有单向绑定,必然也有双向绑定。单向绑定是数据改变带动UI改变,双向绑定则是UI界面改变会改变数据。 为了能够更好的展示双向绑定,这里对UI界面做个改动,界面上布置上两个SeekBar。代码如下:
<?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>
<import type="com.work.binding.practice.data.ProgressData" />
<variable
name="progressData"
type="ProgressData" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatSeekBar
android:id="@+id/first_seek_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:max="100"
android:progress="@={progressData.progress}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatSeekBar
android:id="@+id/second_seek_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:max="100"
android:progress="@={progressData.progress}"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/first_seek_bar" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
实现双向绑定很简单,只需要改动UI界面上的@{progressData.progress} 改为@={progressData.progress} 即可。当然除了使用DataBinding,也可以用ViewModel+LiveData来实现。
总结
数据更新可以继承BaseObservable或者使用ObservableXXX类,实现双向绑定,则需要在UI界面使用@={progressData.progress} 来绑定
|