View Binding in Android (Kotlin)
Whenever we start a project the first and most tedious task is to initialize each view from our layout by using findViewById()
. Here, viewBinding can be your new best-friend to save your time and simplify your code.
You must be wondering What is View Binding? As per documentation
View binding is a feature that makes it easier to write code that interacts with views. Once view binding is enabled in a module, it generates a binding class for each XML layout file present in that module. An instance of a binding class contains direct references to all views that have an ID in the corresponding layout.
In short, viewBinding is the replacement for findViewById()
. It makes coding experience smooth and you can avoid all the boilerplate of findViewById()
.
Advantages:
- Null Safety
- Type Safety
- Faster compilation
- Type Safety
Limitations:
- Cannot be used to declare dynamic UI content straight from XML layout files.
- Does not support two way binding.
Now the question is, How do you can achieve this?
From Android Studio 3.6, viewBinding is a built-in feature, you do not need to implement any extra libraries to enable it. To enable viewBinding, you just need to configure viewBinding
in your module level build.gardle
.
// Android Studio 3.6
android {
viewBinding {
enabled = true
}
}
// Andoird Studio 4.0
andoird {
buildFeatures {
viewBinding = true
}
}
Once you enable viewBinding, it will generate binding classes for all the layouts without making changes in your XML files.
Now, it’s time to use those auto-generated layout binding classes and save our time. We normally uses four types of layout files:
- Activities
- Fragments
- Dialogs
- RecyclerView Adapters
so let’s see how to use viewBinding in these one-by-one.
Activity:
To use viewBinding in activities you need to replace setContentView(R.layout.activity_main)
with folloing code:
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.textView.text = "Hello, World!"
}
}
In above code, ActivityMainBinding
is a auto-generated binding class of activity_main.xml
. You can access any view added in your activity_main.xml
.
Here’s how it works:
ActivityMainBinding.inflate(layoutInflater)
inflates the layout file associated with theActivityMainBinding
class. Theinflate()
method takes an instance ofLayoutInflater
(usually obtained fromgetLayoutInflater()
orLayoutInflater.from(context)
) and inflates the layout XML file, creating an instance of theActivityMainBinding
class.setContentView(binding.root)
sets the root view of the activity to the root view of the inflatedActivityMainBinding
instance. Theroot
property represents the root view of the layout file.- In
binding.textView.text = "Hello, World!"
,binding
refers to the instance ofActivityMainBinding
,textView
represents theTextView
view in your layout file.
Fragment:
You need to code in onCreateView()
method something like this:
class MainFragment : Fragment() {
lateinit var binding: FragmentMainBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = FragmentMainBinding.inflate(layoutInflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.textView.text = "Hello, World!"
}
}
Here’s how it works:
binding = FragmentMainBinding.inflate(layoutInflater, container, false)
inflates the layout file associated with theFragmentMainBinding
class, using the providedLayoutInflater
andViewGroup
container. The third parameter,false
, indicates that the inflated view should not be attached to the container immediately.return binding.root
returns the root view of the inflated layout as the fragment's view.
Dialog:
At the time of dialog creation or initialization, you need to use following code to use DailogLayout’s view through binding.
dialogBinding: LayoutDialogBinding = LayoutDialogBinding.inflate(LayoutInflater.from(this))
val dialog = Dialog(this)
dialog.setContentView(dialogBinding.root)
dialogBinding.textView.text = "Hello, World!"
RecyclerView Adapter:
class MyAdapter(val context: Context, private val itemList: List<DataClass>)
: RecyclerView.Adapter<MyAdapter.ViewHolder>() {
class ViewHolder(val itemBinding: SingleViewBinding)
: RecyclerView.ViewHolder(itemBinding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemBinding = SingleViewBinding.inflate(LayoutInflater.from(context), parent, false)
return ViewHolder(itemBinding)
}
override fun getItemCount(): Int {
return itemList.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.apply {
with(itemList[position]) {
itemBinding.textView.text = this.message
}
}
}
}
Here, you can use inner class
as well for ViewHolder
class if you want to.
When generating binding classes, you can ignore a layout by adding tools:viewBindingIgnore=”true”
to its root view. In this attribute, the data binding compiler ignores the layout and does not generate binding classes.
I hope this article has provided valuable insights and assistance for your Android journey. Your support means a lot to me, so if you found this content helpful, don’t hesitate to show some love with a hearty round of applause!👏
Your feedback fuels my passion for creating quality content. For any Android queries or just to connect, reach out on LinkedIn and Twitter.
Thanks for reading — looking forward to staying in touch!
Happy Coding!!