欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android DataBinding单向绑定

程序员文章站 2022-04-20 08:31:48
...

Android DataBinding单向绑定


一、Android DataBinding 基础使用
二、Android DataBinding单向绑定
三、Android DataBinding 双向数据绑定、事件绑定、使用类方法


DataBinding 是google发布的一个数据绑定框架,用于降低布局和逻辑的耦合性,使代码逻辑更加清晰。大量减少 Activity 内的代码,数据能够单向或双向绑定到 layout 文件中,有助于防止内存泄漏,而且能自动进行空检测以避免空指针异常。

实现数据变化自动驱动 UI 刷新的方式有三种:BaseObservableObservableFieldObservableCollection

BaseObservable

一个简单的ViewModel 类被更新后,并不会让 UI 自动更新。而数据绑定后,我们自然会希望数据变更后 UI 会即时刷新,Observable 就是为此而生的概念。

BaseObservable 提供了 notifyChange()notifyPropertyChanged() 两个方法。

  • notifyChange()

它会刷新所有的值。

  • notifyPropertyChanged()

它只会根据对应的BRflag更新,该 BR 的生成通过注释 @Bindable 生成,可以通过 BR notify 特定属性关联的视图。

  • 由于kotlin的属性默认是public修饰,所以可以直接在属性上@Bindable, 如何设置了修饰符且不为public的话,则可使用@get BIndable(表示在get()方法上标记@Bindable
import androidx.databinding.BaseObservable
import androidx.databinding.Bindable
import com.github.ixiaow.sample.BR

class UserInfo : BaseObservable() {
	// 对name进行@Bindable标志,然后会生成BR.name
    @Bindable
    var name: String = ""
        set(value) {
            field = value
            // 当name,发生改变时只会刷新与name相关控件的值,不会刷新其他的值
            notifyPropertyChanged(BR.name)
        }

    @get: Bindable
    var password: String = ""
        set(value) {
            field = value
            // 当password 发生改变时,也会刷新其他属性相关的控件的值
            notifyChange()
        }
}

布局文件:

<?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="userInfo" type="com.github.ixiaow.sample.model.UserInfo"/>
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MainActivity">

        <TextView
                app:layout_constraintVertical_chainStyle="spread"
                android:id="@+id/mUserName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{userInfo.name}"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>

        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{userInfo.password}"
                app:layout_constraintTop_toBottomOf="@id/mUserName"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"/>

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

    实现了 Observable 接口的类允许注册一个监听器OnPropertyChangedCallback,当可观察对象的属性更改时就会通知这个监听器。

    当中 propertyId 就用于标识特定的字段

user.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback(){
     override fun onPropertyChanged(sender: Observable, propertyId: Int) {
                
     }
})

ObservableField

继承于 Observable 类相对来说限制有点高,且也需要进行notify 操作,因此为了简单起见可以选择使用 ObservableField。 可以理解为官方对 BaseObservable 中字段的注解和刷新等操作的封装,官方原生提供了对基本数据类型的封装,例如 ObservableBoolean、ObservableByte、ObservableChar、ObservableShort、ObservableInt、ObservableLong、ObservableFloat、ObservableDouble 以及 ObservableParcelable ,也可通过 ObservableField 泛型来申明其他类型。

data class ObservableUser(
    var name: ObservableField<String>,
    var password: ObservableField<String>
)

ObservableUser属性值的改变都会立即触发 UI 刷新,概念上与Observable 区别不大,具体效果可看下面提供的源代码,这里不再赘述

ObservableCollection

dataBinding 也提供了包装类用于替代原生的 ListMap,分别是 ObservableListObservableMap,当其包含的数据发生变化时,绑定的视图也会随之进行刷新

<?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>
        <import type="androidx.databinding.ObservableList"/>
        <import type="androidx.databinding.ObservableMap"/>
        <import type="com.github.ixiaow.sample.model.User"/>
        <variable name="index" type="int"/>
        <variable name="key" type="String"/>
        <variable name="list" type="ObservableList&lt;User>"/>
        <variable name="map" type="ObservableMap&lt;String, User>"/>
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MainActivity">

        <TextView
                app:layout_constraintVertical_chainStyle="spread"
                android:id="@+id/mUserName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{list[index].name}"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>

        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{map[key].password}"
                app:layout_constraintTop_toBottomOf="@id/mUserName"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val dataBinding: ActivityMainBinding =
            DataBindingUtil.setContentView(this, R.layout.activity_main)
        
        dataBinding.map = ObservableArrayMap<String, User>().apply {
            "android" to User("android", "12367")
            "java" to User("java", "12534")
            "c" to User("c", "12344")
            "c++" to User("c++", "14423")
            "c#" to User("c#", "12334")
        }

        dataBinding.key = "c"

        dataBinding.list = ObservableArrayList<User>().apply {
            add(User("android", "123"))
            add(User("java", "1234"))
            add(User("c", "1235"))
            add(User("c++", "123447"))
        }

        dataBinding.index = 3
    }
}

本地址:https://blog.csdn.net/xiaowu_zhu/article/details/91876068