Data Binding Library
In Android development, data binding is facilitated by the Data Binding Library, which generates binding classes at compile time for XML layouts. This library is integrated with Android's build system and supports binding expressions in XML layouts.
Binding Expressions
in XML layouts, you can use binding expressions to bind UI elements (like TextViews, EditTexts, etc.) directly to fields or methods in your Kotlin code. For example, you can bind a TextView to a variable.
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{variablename.userName}" />
Two Way Binding
Data binding in Kotlin also supports two-way data binding, where changes in the UI update the underlying data model and vice versa. For example, you can bind an EditText to a variable and automatically update the variable whenever the user types something in the EditText.
<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@={variablename.userInput}" />
In the below example, we are going to pass data from one Fragment to another using the concept of Two-way Binding.
1. Enable Data Binding in build.gradle.kts (Module::app)
android {
buildFeatures {
dataBinding = true
}
}
actvity_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:tools="http://schemas.android.com/tools">
<FrameLayout
android:id="@+id/HomeFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
</FrameLayout>
</layout>
MainActvity.kt
package com.example.databindingoneway
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import com.example.databindingoneway.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
supportFragmentManager.beginTransaction()
.replace(R.id.HomeFrame, LoginFragment())
.commit()
}
}
Create a class Profile.kt
package com.example.databindingoneway
class Profile(var name: String = "", var pass: String = "")
fragment_login.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="data"
type="com.example.databindingoneway.Profile" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoginFragment">
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/nameET"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginHorizontal="20dp"
android:hint="@string/enter_name"
android:text="@={data.name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/passET"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginHorizontal="20dp"
android:hint="@string/enter_password"
android:text="@={data.pass}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/nameET"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/loginBTN"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/submit"
android:layout_marginTop="20dp"
android:layout_marginHorizontal="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/passET"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
LoginFragment.kt
package com.example.databindingoneway
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.databindingoneway.databinding.FragmentLoginBinding
class LoginFragment : Fragment() {
private lateinit var binding: FragmentLoginBinding
private val bundle = Bundle()
private val fragment = HomeFragment()
val profile = Profile()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentLoginBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initUI()
}
private fun initUI() {
binding.data = profile
binding.loginBTN.setOnClickListener {
bundle.apply {
putString("name", profile.name)
putString("pass", profile.pass)
}
fragment.arguments = bundle
requireActivity().supportFragmentManager.beginTransaction()
.replace(R.id.HomeFrame, fragment)
.addToBackStack(null)
.commit()
}
}
}
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="data"
type="com.example.databindingoneway.Profile" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeFragment">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/nameTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textSize="16sp"
android:text="@{data.name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/passTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textSize="16sp"
android:text="@{data.pass}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/nameTV"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
HomeFragment.kt
package com.example.databindingoneway
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.databindingoneway.databinding.FragmentHomeBinding
class HomeFragment : Fragment() {
private lateinit var binding: FragmentHomeBinding
private val profile = Profile()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
arguments?.let {
profile.name = it.getString("name")!!
profile.pass = it.getString("pass")!!
}
binding.data = profile
}
}