The Data Binding Library is a support library that allows you to bind UI components in your layouts to data sources in your app using a declarative format rather than programmatically. It is basically removed the need of using findViewById<>() and we put data on the xml layout fiile itself.
Preparation :
Enable the data binding feature on your build.gradle
android {
...
dataBinding {
enabled true
}
}
Now we can convert the layout to a Data Binding layout.
1. Wrap your layout with a <layout>
tag
2. Add layout variables (optional)
3. Add layout expressions (optional)
Now our layout should look like this
<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>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
...
We can bind our data in data column. Let us try to bind simple String data to be display in TextView :
<?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>
<variable
name="stringData"
type="String" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{stringData}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Now that the stringData variable has been bind to our layout, we can set the stringData content programmatically.
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
//set stringData programmatically
binding.stringData = "This data set programmatically"
}
}
Bind viewmodel to handle userEvents and actions also possible. As shown on bellow snippet, we can bind viewModel to layout, and also bind action from its viewModel.
...
<data>
<variable
name="mainVM"
type= "com.andreasgift.medium_databinding.MainViewModel"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{mainVM.stringData}"
android:onClick="@{() -> mainVM.actionVM()}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
This means we can observe LiveData from Activity and layout will automatically display it.
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
private val viewModel by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
viewModel.stringData.observe(this, Observer {
binding.mainVM = viewModel
})
}
}
We can also custom field data on our layout with Binding Adapter. For example, lets create custom field data that will display whether the TextView will be Visible or Gone
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{mainVM.stringData}"
android:onClick="@{() -> mainVM.actionVM()}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:visibleOrGone = "@{mainVM.visibleOrGone()}"/>
Next, we need to create the BindingAdapter that will tell our layout what should we do with the view after we get this data. We can create new class called MyBindingAdapter :
object MyBindingAdapter {
@BindingAdapter("app:visibleOrGone")
@JvmStatic
fun setVisibility(view: View, data: Boolean) {
if (data) {
view.visibility = View.VISIBLE
} else {
view.visibility = View.GONE
}
}
}
The last step, dont forget to import our new BindingAdapter to its layout.
<data>
<variable
name="mainVM"
type= "com.andreasgift.medium_databinding.MainViewModel" />
<import type="com.andreasgift.medium_databinding.MyBindingAdapter"/>
</data>
Last cheat sheet, on how to display data binding from Fragment. We need to create binding getter.
class MainFragment : Fragment() {
private var _binding: FragmentMainBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentMainBinding.inflate(layoutInflater, container, false)
val view = binding.root
return view
}
}
That is all for Android Data Binding. I hope it will help for other developer to understand it deeper.