DataBinding的使用三

一、前言

上文记录了DataBinding的表达式的使用,这一篇继续对可观察对象的使用进行记录

二、可观察字段

这里引用一下官网的介绍

可观察性是指一个对象将其数据变化告知其他对象的能力。通过数据绑定库,您可以让对象、字段或集合变为可观察。

任何 plain-old 对象都可用于数据绑定,但修改对象不会自动使界面更新。通过数据绑定,数据对象可在其数据发生更改时通知其他对象,即监听器。可观察类有三种不同类型:对象字段集合

当其中一个可观察数据对象绑定到界面并且该数据对象的属性发生更改时,界面会自动更新。

这里举个例子来说明可观察性的作用,先看下没有使用可观察字段的代码,这里使用普通的类进行数据绑定,用来显示个内容

activity_main.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"
    xmlns:bind="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

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

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

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/update_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="@{change}"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            tools:text="value" />

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

MainActivity.kt

class MainActivity : AppCompatActivity() {
    
    
    private var changeValue = "你好啊"
    private val binding: ActivityMainBinding by lazy {
    
    
        ActivityMainBinding.inflate(layoutInflater)
    }
    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        binding.change = changeValue
        changeValue = "我不好"
    }
}

这个代码先使用字符串和xml进行绑定,后续又更改这个字符串。结果是可以预料的,后面改变的内容不会显示到UI布局上,这是很正常的现象。但是在项目中,假设这个字段需要更改很多次,那么每次都要在赋值之后重新执行一下binding.change = changeValue会显的很繁琐。所以这里引入了可观察字段的功能,下面看修改后的代码

activity_main.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"
    xmlns:bind="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="change"
            type="androidx.databinding.ObservableField<String>" />

    </data>

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

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/update_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="@{change}"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            tools:text="value" />


        <androidx.appcompat.widget.AppCompatEditText
            android:id="@+id/input"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toBottomOf="@+id/update_content"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>

        <androidx.appcompat.widget.AppCompatTextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="@{input.text}"
            app:layout_constraintTop_toBottomOf="@+id/input"
            app:layout_constraintStart_toStartOf="parent" />


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

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private val changeValue = ObservableField<String>("你好啊")
    private val binding: ActivityMainBinding by lazy {
        ActivityMainBinding.inflate(layoutInflater)
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        binding.change = changeValue
        changeValue.set("我不好")
    }
}

这样修改完就可以做到当字符串内容更改后UI就实时更改了。

DataBinding中提供的基础可观察字段有以下几种

在创建实现 Observable 接口的类时要完成一些操作,但如果您的类只有少数几个属性,这样操作的意义不大。在这种情况下,您可以使用通用 Observable 类和以下特定于基元的类,将字段设为可观察字段:

例如我们新建一个保存用户信息的类,可以将可观察到变量填充进去

    class User {
    
    
        val firstName = ObservableField<String>()
        val lastName = ObservableField<String>()
        val age = ObservableInt()
    }

三、可观察集合

除了可观察字段外,还有一些可观察集合,主要是ObservableArrayMapObservableArrayList

    ObservableArrayMap<String, Any>().apply {
    
    
        put("firstName", "Google")
        put("lastName", "Inc.")
        put("age", 17)
    }

    ObservableArrayList<Any>().apply {
    
    
        add("Google")
        add("Inc.")
        add(17)
    }
<data>
        <import type="android.databinding.ObservableMap"/>
        <variable name="user" type="ObservableMap<String, Object>"/>

        <import type="android.databinding.ObservableList"/>
        <import type="com.example.my.app.Fields"/>
        <variable name="user2" type="ObservableList<Object>"/>
    </data><TextView
        android:text="@{user.lastName}"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView
        android:text="@{String.valueOf(1 + (Integer)user.age)}"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

     <TextView
        android:text='@{user2[Fields.LAST_NAME]}'
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView
        android:text='@{String.valueOf(1 + (Integer)user2[Fields.AGE])}'
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

四、可观察对象

有时候官方提供的方式不能满足需求,需要自己拓展,这时候可以实现Observable来完成这一功能

    class User : BaseObservable() {
    
    

        @get:Bindable
        var firstName: String = ""
            set(value) {
    
    
                field = value
                notifyPropertyChanged(BR.firstName)
            }

        @get:Bindable
        var lastName: String = ""
            set(value) {
    
    
                field = value
                notifyPropertyChanged(BR.lastName)
            }
    }
    

以下引用自官方文档

数据绑定在模块包中生成一个名为 BR 的类,该类包含用于数据绑定的资源的 ID。在编译期间,Bindable 注释会在 BR 类文件中生成一个条目。如果数据类的基类无法更改,Observable 接口可以使用 PropertyChangeRegistry 对象实现,以便有效地注册和通知监听器。

实现Observable接口的方式

class User : Observable {
    
    

    private val property : PropertyChangeRegistry by lazy {
    
    //默认是线程安全的
        PropertyChangeRegistry()
    }

    @get:Bindable
    var change: String = ""
        set(value) {
    
    
            field = value
            notifyPropertyChanged(BR.change)
        }

    override fun addOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) {
    
    
        property.add(callback)
    }

    override fun removeOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) {
    
    
        property.remove(callback)
    }

    fun notifyChange(){
    
    
        property.notifyCallbacks(this, 0, null)
    }
    fun notifyPropertyChanged(fieldId : Int) {
    
    
        property.notifyCallbacks(this, fieldId, null);
    }
}

五、参考链接

  1. 使用可观察的数据对象  |  Android 开发者  |  Android Developers

猜你喜欢

转载自blog.csdn.net/Mr_Tony/article/details/124255550