Android Data Binding (Kotlin) Part 2

Photo by Sajad Nori on Unsplash

Continuation
I have showed basis features in the previous part. In this article I’ll show the main features of Data Binding.
Undoubtedly if you didn’t face with Data Binding later, you should read my previous part about Data Binding. It doesn’t take plenty of time.
Code in layout
You will have a lot of cases when you need to set a field with not type String.

data class Person(
var id: Long,
var name: String,
var surname: String,
var salary: Int
)

You can solve this problem throw Data Binding in the xml file. You can write some code in the xml file as in the field.

<?xml version="1.0" encoding="utf-8"?>
<layout>

<data>

<variable
name="model"
type="com.ostrovec.databinding.Person" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{"name =" + model.name + " surname = " + model.surname}'
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(model.salary+200)}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />

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

As you can see, I used the method of the String class and I converted Int to String. Also I concatenated two strings and wrote labels there.

<?xml version="1.0" encoding="utf-8"?>
<layout>

<data>

<import type="com.ostrovec.databinding.Util"/>
<import type="android.view.View"/>
<variable
name="model"
type="com.ostrovec.databinding.Person" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:id="@+id/main_name_surname_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{"name =" + model.name + " surname = " + model.surname}'
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/main_current_time_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{model.salary > 1200 ? View.GONE: View.VISIBLE}"
android:text="@{Util.getCurrentTime()}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />

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

Now, you can see that I used my static method for getting current time. For it you should import the class in xml file. Also I have showed the example with visibility. You can write some logic in code, but if you have a difficult logic then you should extract it in other method. And you manage to apply this method using a Binging Adapter or import a static method.

Getting an access to views in code.
I often have situations when I have to get access to views in code. We can access to views without the method findViewById().
Look at the previous example code of the xml file. The Data Binding generates a view by id.

class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

binding = DataBindingUtil.setContentView(this,R.layout.activity_main)
binding.model = getPerson()
initListeners()
}

private fun initListeners(){
binding.mainNameSurnameTextView.setOnClickListener {
Log.e("TAG","click on the first text view")
}
binding.mainCurrentTimeTextView.setOnClickListener {
Log.e("TAG","click on the second text view")
}
}

private fun getPerson():Person{
return Person(0,"Alex","Dervanouskas",1000)
}
}

Handlers
I set click listeners on text views in code. But we should extract it.
At the beginning you should create interface.

interface PersonHandler {
fun clickOnName()

fun clickOnTime()
}

Next you should add this interface in your xml file and link methods of this interface with views.

<data>

<import type="com.ostrovec.databinding.Util" />

<import type="android.view.View" />

<variable
name="model"
type="com.ostrovec.databinding.Person" />

<variable
name="handler"
type="com.ostrovec.databinding.PersonHandler" />
</data>
<TextView
android:id="@+id/main_name_surname_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{"name =" + model.name + " surname = " + model.surname}'
android:onClick="@{() -> handler.clickOnName()}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/main_current_time_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{Util.getCurrentTime()}"
android:onClick="@{() -> handler.clickOnTime()}"
android:visibility="@{model.salary > 1200 ? View.GONE: View.VISIBLE}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />

Finally you should initialize the interface and set handler in the binding field.

class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding
private val personHandler = object: PersonHandler{
override fun clickOnName() {
Log.e("TAG","click on the first text view")
}

override fun clickOnTime() {
Log.e("TAG","click on the second text view")
}

}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

binding = DataBindingUtil.setContentView(this,R.layout.activity_main)
binding.model = getPerson()
binding.handler = personHandler
}

private fun getPerson():Person{
return Person(0,"Vlad","Erchik",1700)
}
}

Include
There are cases when we have to use the other layout.

content_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: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>

The part of code of activity_main.xml

<include layout="@layout/content_main"
bind:model="@{model}"/>

Variables may be passed into an included layout’s binding from the containing layout by using the app namespace and the variable name in an attribute. Data binding doesn’t support include as a direct child of a merge element.