Data Binding in Android Kotlin

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

Binding

Output


Similar Articles