To avoid findViewById, create an object that contains a reference to each view. This object, called a Binding object, can be used by your whole app. Once a binding object has been created for your app, you can access the views, and other data, through the binding object, without having to traverse the view hierarchy or search for the data.
There are 2 ways for doing this -> DataBinding & ViewBinding.
- ViewBinding = Only binding views to code
- DataBinding = Binding data (from code) to views + ViewBinding (Binding views to code)
Both have the following benefits:
- Code is shorter, easier to read, and easier to maintain than code that uses findViewById().
- The Android system only traverses the view hierarchy once to get each view, and it happens during app startup, not at runtime when the user is interacting with the app.
- You get type safety for accessing views. (Type safety means that the compiler validates types while compiling, and it throws an error if you try to assign the wrong type to a variable.)
DataBinding has 1 extra benefit
- Data and views are clearly separated. This is a very major benefit.
First solution is to do Viewbinding.
To enable view binding, do this in app level build.gradle
buildFeatures {
viewBinding true
}
apply plugin kotlin-kapt
// if you’re using kotlin instead of groovy
Read more about it here https://kotlinlang.org/docs/kapt.html
android {
viewBinding {
enabled = true
}
Then in your activity
private lateinit var binding: ActivityMainBinding
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
Now change findViewByIds like this.
binding.nicknameText.text = binding.nicknameEdit.text
binding.nicknameEdit.visibility = View.GONE
binding.doneButton.visibility = View.GONE
binding.nicknameText.visibility = View.VISIBLE
Kotlinize the function by using apply{}.
binding.apply {
nicknameText.text = nicknameEdit.text.toString()
nicknameEdit.visibility = View.GONE
doneButton.visibility = View.GONE
nicknameText.visibility = View.VISIBLE
}
Neat?
Let’s look at second approach - Data binding.
DataBinding internally uses Annotation processor to generate bindings and set other properties.
If you are
To enable data binding
buildFeatures {
dataBinding true
}
Second
Add
Third in your activity
private lateinit var binding: ActivityMainBinding
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
//inside fragments onCreateView
val binding = DataBindingUtil.inflate<FragmentTitleBinding>(inflater, R.layout.placeholder_layout, container, false)
return binding.root
You can take advantage of data binding to make a data class directly available to a view. This technique simplifies the code, and is extremely valuable for handling more complex cases.
Step 1 - Create a data class.
data class MyName(var name: String = "", var nickname: String = "")
Step 2 - Add data to the layout.
At the top of the layout, between the
<data>
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
</data>
Now access this varible in the layout
@={} is a directive to get the data that is referenced inside the curly braces.
android:text="@={myName.name}"
Step 3 - Create the data.
private val myName: MyName = MyName("Sahil")
binding.myName = myName
binding.invalidateAll()
invalidateAll() makes UI refreshed with the value in the updated binding object.
Is there any other difference in app size?
This is what I noticed in a small app. There could be major difference in size for a prod app. So consider using between both view binding & data binding.
╔═══════════════╦═══════╦═══════════════╦═════════╗
║ Databinding ║ Size ║ ViewBinding ║ Size ║
╠═══════════════╬═══════╬═══════════════╬═════════╣
║ androidx ║ ║ androidx ║ ║
║ –databinding ║ 72 Kb ║ –viewbinding ║ 275 B ║
║ –viewbinding ║ 275 B ║ ║ ║
╚═══════════════╩═══════╩═══════════════╩═════════╝
Thanks for reading!