Android Data Binding (Kotlin) Part 3
Overview
This is the article about Data Binding. After learning of this article you manage to assume that you have studied Data Binding.
Undoubtedly if you didn’t face with Data Binding later, you should read my previous parts about Data Binding. It doesn’t take plenty of time.
Continuation
You will have a lot situations, when you data is changeable. Data updating can occur on the server or in another storage and you will need to show new data. Consider the simple example.
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var person = getPerson()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.model = person
Handler().postDelayed({
person.name = "Alla"
}, 2000)
}
private fun getPerson(): Person {
return Person(0, "Alex", "Ivanov", true)
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="model"
type="com.ostrovec.databinding.Person" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/main_name_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{model.name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
You can see, that we out person has “Alex” name and we change the person name in 2000 milliseconds. But after running you can see invariable result.
If you change the model, you can’t see some changes. You manage to fix it, if you set new model in binding.
Handler().postDelayed({
person.name = "Alla"
binding.model = person
}, 2000)
After setting model you will see new name in 2000 milliseconds.
We considered a simple and not the best solution to this problem, because the model can is changed a lot of time and after every time we need to set new model. I’ll show the better solution.
Observable data
Observability refers to the capability of an object to notify others about changes in its data. The Data Binding Library allows you to make objects, fields, or collections observable.
Person.kt
data class Person(
var id: Long,
val name: ObservableField<String> = ObservableField(),
val surname: ObservableField<String> = ObservableField(),
val isAdmin: ObservableField<Boolean> = ObservableField()
)
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var person = getPerson()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.model = person
Handler().postDelayed({
person.name.set("Alla")
}, 2000)
}
private fun getPerson(): Person {
var person = Person(0)
person.name.set("Alex")
person.surname.set("Ivanov")
person.isAdmin.set(true)
return person
}
}
After addition observable fields we don’t need to set the model in binding. The textView will have the text “Alex” and in 2000 milliseconds will have the text “Alla”. When the model is changed, the textView changes the text.
BaseObservable
We can don’t use observable fields, we can use for observing data the second option.
Person.kt
import androidx.databinding.BaseObservable
import androidx.databinding.Bindable
data class Person(var id: Long) : BaseObservable() {
@get: Bindable
var name: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.name)
}
@get: Bindable
var surname: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.surname)
}
@get: Bindable
var admin: Boolean = false
set(value) {
field = value
notifyPropertyChanged(BR.admin)
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var person = getPerson()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.model = person
Handler().postDelayed({
person.name = "Alla"
}, 2000)
}
private fun getPerson(): Person {
var person = Person(0)
person.name = "Alex"
person.surname = "Ivanov"
person.admin = true
return person
}
}
You should inherit your model from the BaseObservable class. When you add notifyPropertyChanged() you can catch error wit text “Unresolved reference: BR”. You should add string “ apply plugin: “kotlin-kapt” ” in build.gradle file.
And now the TextView is being changed text after changing in the model.
Two-way data binding
Your model can be updated after changing views automatically. You don’t need to write the extra logic in your activity or fragment.
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var person = getPerson()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.model = person
Handler().postDelayed({
Log.e("tag", "${person.admin}")
}, 4000)
}
private fun getPerson(): Person {
var person = Person(0)
person.name = "Alex"
person.surname = "Ivanov"
person.admin = true
return person
}
}
activity_main.xml
For two-way data binding you have to add sign “=” in xml file. In this example I added this sign, where is located android:checked attribute.
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="model"
type="com.ostrovec.databinding.Person" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox
android:id="@+id/main_admin_check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@={model.admin}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Person.kt
data class Person(var id: Long) : BaseObservable() {
@get: Bindable
var name: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.name)
}
@get: Bindable
var surname: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.surname)
}
@get: Bindable
var admin: Boolean = false
set(value) {
field = value
notifyPropertyChanged(BR.admin)
}
}
At the begging the field admin is equals true, but you can change your checkbox and value of this field will be changed. It often used with editTexts.
Сonclusion
I showed the basis in three articles. I hope that these articles help you.