So we talked about the basics of DataBinding. BaseObservable DataBinding BaseObservable DataBinding BaseObservable BindingAdapter and BindingConversion DataBinding advanced section 4-way DataBinding

Three: Using observable data objects (one-way data binding)

There are three ways to implement data changes and automatically notify UI updates: BaseObservable, ObservableField, and ObservableCollection

3.1 BaseObservable

Implementing the Observable interface has mechanisms for adding and removing listeners, but you must decide when to send notifications. For development purposes, the data binding library provides a BaseObservable class that implements the listener registration mechanism. The data class that implements a BaseObservable notifies properties when they change. This is done by assigning the Bindable annotation to the getter and then calling the notifyPropertyChanged() method in the setter. Create an ObserableUser class that extends from BaseObservable, as shown in the following example

class ObserableUser :BaseObservable() {@get:Bindable
    var name = ""
        set(value) {
            field = value
            // Refresh the current property only
            notifyPropertyChanged(BR.name)
        }

    var price = 0f

    @get:Bindable
    var age = 0
        set(value) {
            field = value
            // Update all fields
            notifyChange()
        }
}
Copy the code
  • @get:Bindable Generates the BR class with the Bindable annotation get method
  • The notifyPropertyChanged() method notifies updating a field, above which is updating only Br.name, which is generated using the @bindable annotation
  • NotifyChange () updates all fields

The code in the activity_main.xml file is as follows:

<? 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="com.example.jetpackdatabindingtestapp.ui.helper.ClickHelper" />
        <import type="com.example.jetpackdatabindingtestapp.ui.model.ObserableUser" />
        <variable name="obserableUser" type="ObserableUser" />
        <variable name="clickHelper"  type="ClickHelper" />
    </data>

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

         <TextView
            android:id="@+id/tv_obserable_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{obserableUser.name}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/tv_obserable_age"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@ {String. The valueOf (obserableUser. Age) + ', '}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/tv_obserable_name" />

        <TextView
            android:id="@+id/tv_obserable_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@ {String. The valueOf (obserableUser. Price) + 'yuan'}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/tv_obserable_age" />

        <Button
            android:id="@+id/btn_change_user_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{()->clickHelper.onChangeName(obserableUser)}"
            android:text="Change your name"
            app:layout_constraintEnd_toStartOf="@+id/btn_change_user_age"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/tv_obserable_price" />

        <Button
            android:id="@+id/btn_change_user_age"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{()->clickHelper.onChangeAge(obserableUser)}"
            android:text="Change your age."
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/btn_change_user_name"
            app:layout_constraintTop_toBottomOf="@+id/tv_obserable_price" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Copy the code

ClickHelper class

class ClickHelper() {fun onChangeName(userObserableUser: ObserableUser){
        userObserableUser.name +=userObserableUser.age
        userObserableUser.price++
    }

    fun onChangeAge(userObserableUser: ObserableUser){
        userObserableUser.age++
        userObserableUser.price++
    }

}
Copy the code

MainActivity

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this,R.layout.activity_main)
        val observableUser = ObserableUser()
        observableUser.name = "ccm"
        observableUser.age = 21
        binding.obserableUser = observableUser
        binding.clickHelper = ClickHelper()
    }
}
Copy the code

The refresh of name does not refresh price at the same time as the refresh of age does. When the attribute value change, will be a OnPropertyChangedCallback callback, we could add OnPropertyChangedCallback monitor

obserableUser.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
            override fun onPropertyChanged(sender: Observable? , propertyId:Int) {
                when(propertyId){
                    BR.name->{}
                    BR._all->{}
                    BR.age->{}
                    else- > {}}}})Copy the code

3.2 ObservableField

It is relatively complicated to use ObservableField inherited from Observable class and requires notify operation to refresh UI. If our property definition is simple, ObservableField can be used. ObservableField is an official encapsulation of field annotation and refresh operations in a BaseObservable. The ObservableField can be used directly to refresh UI by modifying property values.

  • ObservableBoolean
  • ObservableByte
  • ObservableChar
  • ObservableShort
  • ObservableInt
  • ObservableLong
  • ObservableFloat
  • ObservableDouble
  • ObservableParcelable

ObservableField

, ObservableField

, ObservableField

Create a Teacher class with three properties firstName, teacherAge, and price


class Teacher{
    val firstName = ObservableField<String>()
    val teacherAge = ObservableInt()
    val price = ObservableDouble()
}
Copy the code

One activity_field. XML layout, three text, three buttons. Three text displays firstName, teacherAge, price values, and three buttons change firstName, teacherAge, price values

<? 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="com.example.jetpackdatabindingtestapp.ui.model.Teacher" />
        <import type="com.example.jetpackdatabindingtestapp.ui.helper.ClickTeacherHelper"/>

        <variable
            name="teacher"
            type="Teacher" />

        <variable
            name="clickTeacherHelper"
            type="ClickTeacherHelper" />

    </data>

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

        <TextView
            android:id="@+id/tv_teacher_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{teacher.firstName}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/tv_teacher_age"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{string.valueof (teacher.teacherage)+ 'old teacher'}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/tv_teacher_name" />

        <TextView
            android:id="@+id/tv_teacher_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@ {String. The valueOf (the teacher) price) + ` yuan `}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/tv_teacher_age" />

        <Button
            android:id="@+id/btn_change_teacher_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Change your name"
            android:onClick="@{()->clickTeacherHelper.onChangeName(teacher)}"
            app:layout_constraintEnd_toStartOf="@+id/btn_change_teacher_age"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/tv_teacher_price" />

        <Button
            android:id="@+id/btn_change_teacher_age"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Change your age."
            android:onClick="@{()->clickTeacherHelper.onChangeAge(teacher)}"
            app:layout_constraintEnd_toStartOf="@+id/btn_change_teacher_price"
            app:layout_constraintStart_toEndOf="@+id/btn_change_teacher_name"
            app:layout_constraintTop_toBottomOf="@+id/tv_teacher_price" />

        <Button
            android:id="@+id/btn_change_teacher_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Change the price"
            android:onClick="@{()->clickTeacherHelper.onChangePrice(teacher)}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/btn_change_teacher_age"
            app:layout_constraintTop_toBottomOf="@+id/tv_teacher_price" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Copy the code

ClickTeacherHelper, a class that handles events

class ClickTeacherHelper {
    fun onChangeName(teacher: Teacher){
        var name = teacher.firstName.get()? :""
        teacher.firstName.set(name+name)
    }

    fun onChangeAge(teacher: Teacher){
        var age = teacher.teacherAge.get()
        teacher.teacherAge.set(++age)
    }

    fun onChangePrice(teacher: Teacher){
        var price = teacher.price.get()
        teacher.price.set(++price)
    }
}
Copy the code

An Activity class

class FieldActivity :AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<ActivityFieldBinding>(this,R.layout.activity_field)
        val teacher = Teacher()
        teacher.firstName.set("Oh, Chunming Chen.")
        teacher.teacherAge.set(11)
        teacher.price.set(10.0)
        binding.teacher = teacher
        binding.clickTeacherHelper = ClickTeacherHelper()
    }
}
Copy the code

3.3 ObservableCollection

DataBinding also provides the collection List and Map, ObservableList and ObservableMap. The UI can be automatically updated when data changes, as shown in the following example: an Activity class

class FieldActivity :AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<ActivityFieldBinding>(this,R.layout.activity_field)
     
        val observableArrayList = ObservableArrayList<String>()
        observableArrayList.add("Chinese")
        binding.list = observableArrayList
        binding.index = 0

        val observableArrayMap = ObservableArrayMap<String,String>()
        observableArrayMap.put("course"."Chinese")
        binding.map = observableArrayMap
        binding.key = "course"

        binding.btnChangeList.setOnClickListener{
            observableArrayList.clear()
            observableArrayList.add("Mathematics")
            observableArrayMap.clear()
            observableArrayMap.put("course"."Mathematics")}}}Copy the code

A layout file

<? 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="com.example.jetpackdatabindingtestapp.ui.model.Teacher" />

        <import type="com.example.jetpackdatabindingtestapp.ui.helper.ClickTeacherHelper" />

        <import type="androidx.databinding.ObservableArrayMap" />

        <import type="androidx.databinding.ObservableArrayList" />

        <variable
            name="list"
            type="ObservableArrayList< String>" />

        <variable
            name="map"
            type="ObservableArrayMap< String,String>" />

        <variable
            name="index"
            type="int" />

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

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

        <TextView
            android:id="@+id/tv_list_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{list[index]}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/tv_map_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{map[key]}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/tv_list_name" />


        <Button
            android:id="@+id/btn_change_list"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Change the set"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/tv_map_name" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Copy the code