The use of DataBinding three

I. Introduction

The use of expressions recorded above DataBinding, this article continues to record the use of observable objects

Second, the observable field

Here is the introduction of the official website

Observability refers to the ability of an object to inform other objects of changes to its data. With data binding libraries, you can make objects, fields, or collections observable.

Any plain-old object can be used for data binding, but modifying the object does not automatically update the interface. With data binding, data objects can notify other objects, or listeners, when their data changes. There are three different types of observable classes: objects , fields , and collections .

When one of the observable data objects is bound to the interface and the properties of that data object change, the interface updates automatically.

Here is an example to illustrate the role of observability. Let's first look at the code that does not use observable fields. Here, ordinary classes are used for data binding to display content.

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 = "我不好"
    }
}

The code first xmlbinds with the string sum and then changes the string later. The result is to be expected, the content changed later will not be displayed on the UI layout, which is a normal phenomenon. But in the project, assuming that this field needs to be changed many times, it binding.change = changeValuewill be very cumbersome to re-execute each time after the assignment. So the function of observable field is introduced here, let's see the modified code below

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("我不好")
    }
}

In this way, the UI can be changed in real time when the content of the string is changed.

DataBindingThe basic observable fields provided in are as follows

There is some work to be done when creating a class that implements the Observableinterface , but it doesn't make much sense if your class has only a few properties. In this case, you can use the generic Observableclass and the following primitive-specific classes to make the field observable:

For example, if we create a new class to store user information, we can fill in the observable variables.

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

3. Observable collection

In addition to observable fields, there are also observable collections, mainly ObservableArrayMapandObservableArrayList

    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"/>

4. Observable objects

Sometimes the officially provided method cannot meet the needs and needs to be expanded by itself. At this time, it can be implemented Observableto complete this function.

    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)
            }
    }
    

The following is quoted from the official documentation

Data binding generates BRa that contains the ID of the resource used for data binding. During compilation, Bindableannotations generate an entry in the BRclass file. If the base class of the data class cannot be changed, the Observableinterface can be implemented using an PropertyChangeRegistryobject to effectively register and notify listeners.

How to implement Observablethe interface

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);
    }
}

5. Reference links

  1. Using Observable Data Objects | Android Developers | Android Developers

おすすめ

転載: blog.csdn.net/Mr_Tony/article/details/124255550