ViewBinding is a part of Android Jetpack. View binding is a feature that allows you to more easily write code that interacts with views. It replaces the use of findViewById and kotlin synthetics. The View reference it returns is both Type-Safe and Null Safe. Using FindViewById is not null safe as well as not type-safe
So before explaining ViewBinding I will explain Type Safety and Null Safety with examples.
Type Safety
Let’s suppose we are using FindViewById for getting references of views. I will explain this by taking a suitable example.
In the below code I am simply using findViewById for getting the TextView reference this will compile without errors.
class MainActivity : AppCompatActivity[] {
private lateinit var tv1:TextView
override fun onCreate[savedInstanceState: Bundle?] {
super.onCreate[savedInstanceState]
setContentView[R.layout._activitymain_]
tv1 = findViewById[R.id._tvoutput1_]
tv1._text_ = "Hello World"
}
You can see the output Hello World.Now If I just change the type of tv1 to Button it will compile but gives an exception this is the problem with FindViewById it is not Type-Safe. meaning of type safety is that the compiler will validate types while compiling, and throw an error if you try to assign the wrong type to a variable. but in this case, it does clear compilation but throws exception.
class MainActivity : AppCompatActivity[] {
private lateinit var tv1:Button
override fun onCreate[savedInstanceState: Bundle?] {
super.onCreate[savedInstanceState]
setContentView[R.layout._activitymain_]
tv1 = findViewById[R.id._tvoutput1_]
tv1._text_ = "Hello World"
}
}Caused by: java.lang.ClassCastException: com.google.android.material.textview.MaterialTextView cannot be cast to android.widget.Button at com.example.myapplication.MainActivity.onCreate[MainActivity.kt:15] at android.app.Activity.performCreate[Activity.java:7994] at android.app.Activity.performCreate[Activity.java:7978] at android.app.Instrumentation.callActivityOnCreate[Instrumentation.java:1309] at android.app.ActivityThread.performLaunchActivity[ActivityThread.java:3422]
Null Safety
Problem with FindViewById
Now Let’s take the example of the same mainActivity and use the same tv1 variable of type TextView but this time I will create another layout file and add a TextView in that. Now I will use the id of that Text View.
class MainActivity : AppCompatActivity[] {
private lateinit var tv1:TextView
override fun onCreate[savedInstanceState: Bundle?] {
super.onCreate[savedInstanceState]
setContentView[R.layout._activitymain_]
tv1 = findViewById[R.id.**_tvincludeoutput1_**]
tv1._text_ = "Hello World"
}
}This is the XML of another layout.
This will produce this Exception
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myapplication/com.example.myapplication.MainActivity}: java.lang.NullPointerException: findViewById[R.id.tv_include_output1] must not be null
Here this is generated because we are trying to access a view of another layout which is why using FindViewById is not null safe.
Problem with Kotlin Synthetics
Now I will explain the problem with Kotlin Synthetics. for that you need to enable it. just add this ‘kotlin-android-extensions’ in build.gradle[:app] file under plugins.
Now you are good to go
So I will take the same example for explaining it. So now we can directly access view by using their ids only. It will produce the same output as above
tv_output1.text ="Hello World"
Here the view is Type-Safe but not Null-Safe. I can access the TextView present in another layout. it will produce the same NullPointer Exception.
Here I am using the text view which is not associated with activity_main.xml
class MainActivity : AppCompatActivity[] {
override fun onCreate[savedInstanceState: Bundle?] {
super.onCreate[savedInstanceState]
setContentView[R.layout._activitymain_]
tv_include_output1._text_ ="Hello World"
}
}java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myapplication/com.example.myapplication.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method ‘void android.widget.TextView.setText[java.lang.CharSequence]’ on a null object reference
Now I will explain ViewBinding from basics.
View Binding
I will explain how to use view binding in different cases like Activity, Fragment, Custom Views, etc.
Before this, you have to enable view binding go to build.gradle[:app] and add this
buildFeatures*{*
viewBinding true
}Now You can use ViewBinding without any hindrance
First I will start with Activity
Activity
This is how you can use ViewBinding in an Activity. before setContextView just define a variable binding which is of the type ActivityMainBinding.there are many inflate methods for an activity you have to use this inflate method because we don't have any parent view object to pass.
using binding.root you will get the layout root view
class MainActivity : AppCompatActivity[] {
override fun onCreate[savedInstanceState: Bundle?] {
super.onCreate[savedInstanceState]
val binding = ActivityMainBinding.inflate[_layoutInflater_]
setContentView[binding._root_]
binding.tvOutput1._text_="Hello"
binding.tvOutput2._text_="View Binding"
binding.btnClickMe.setOnClickListener **{**
Toast.makeText[_applicationContext_,"Hello TO View Binding",Toast._LENGTHLONG_].show[]
**}**
}
}Output :
Fragment
Now create a BlankFragment.Just follow the below picture
Now in the onCreateView, you can use binding but here the inflate method will change because we have a parent view.
class BlankFragment : Fragment[] {
lateinit var binding: FragmentBlankBinding
override fun onCreateView[inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?]: View {
_// Inflate the layout for this fragment_
binding = FragmentBlankBinding.inflate[inflater,container,false]
binding.fragementTextView._text_ = "I am in Fragment"
return binding._root_
}
companion object {
@JvmStatic fun newInstance[] =
BlankFragment[]
}
}Code to attach Blank Fragment to MainActivity
class MainActivity : AppCompatActivity[] {
override fun onCreate[savedInstanceState: Bundle?] {
super.onCreate[savedInstanceState]
val binding = ActivityMainBinding.inflate[_layoutInflater_]
setContentView[binding._root_]
binding.tvOutput1._text_="Hello"
binding.tvOutput2._text_="View Binding"
binding.btnClickMe.setOnClickListener **{**
Toast.makeText[_applicationContext_,"Hello TO View Binding",Toast._LENGTHLONG_].show[]
**}**
_supportFragmentManager_.beginTransaction[]
.add[R.id._containerfragment_,BlankFragment.newInstance[]]
.commit[]
}
}Custom Views
You can create a custom view just go to UIComponent in the options. Here we are creating a variable binding and initializing it. here we just pass this as parent view group and init block you can initialize your views.
class MainActivity : AppCompatActivity[] {
private lateinit var tv1:Button
override fun onCreate[savedInstanceState: Bundle?] {
super.onCreate[savedInstanceState]
setContentView[R.layout._activitymain_]
tv1 = findViewById[R.id._tvoutput1_]
tv1._text_ = "Hello World"
}
}0
Include Tag
for include tags you just have to mention the id in the layout tag and can get the binding of that included layout by just calling
class MainActivity : AppCompatActivity[] {
private lateinit var tv1:Button
override fun onCreate[savedInstanceState: Bundle?] {
super.onCreate[savedInstanceState]
setContentView[R.layout._activitymain_]
tv1 = findViewById[R.id._tvoutput1_]
tv1._text_ = "Hello World"
}
}1
Merge Tag
For Merge tags, you can’t use ids to get the view. you have to call in onCreate of activity or in onCreateView of fragment
class MainActivity : AppCompatActivity[] {
private lateinit var tv1:Button
override fun onCreate[savedInstanceState: Bundle?] {
super.onCreate[savedInstanceState]
setContentView[R.layout._activitymain_]
tv1 = findViewById[R.id._tvoutput1_]
tv1._text_ = "Hello World"
}
}2
Now I will talk about something which you should not do while using view binding
- Never Add the Custom View as the root and in the custom view don’t use Viewbinding at the same time.
what I want to say is this don’t do both at the same time.
class MainActivity : AppCompatActivity[] {
private lateinit var tv1:Button
override fun onCreate[savedInstanceState: Bundle?] {
super.onCreate[savedInstanceState]
setContentView[R.layout._activitymain_]
tv1 = findViewById[R.id._tvoutput1_]
tv1._text_ = "Hello World"
}
}3
It will result in something like recursive creation of the same view
com.example.myapplication W/e.myapplicatio: at android.view.LayoutInflater.inflate[LayoutInflater.java:657] at android.view.LayoutInflater.inflate[LayoutInflater.java:532] at com.example.myapplication.databinding.SampleMyViewBinding.inflate[SampleMyViewBinding.java:44] at com.example.myapplication.MyView.[MyView.kt:23] at com.example.myapplication.MyView.[MyView.kt:17] at com.example.myapplication.MyView.[MyView.kt:-1] at java.lang.reflect.Constructor.newInstance0[Native method] at java.lang.reflect.Constructor.newInstance[Constructor.java:343] at android.view.LayoutInflater.createView[LayoutInflater.java:852] at android.view.LayoutInflater.createViewFromTag[LayoutInflater.java:1004]
2. Always give unique ids to views otherwise it will mess up.
Try to give unique ids to views in a project. Sometimes the UI you want doesn’t show up with matching ids.
3. Custom Views parent is itself that Custom View when added dynamically.
you can also try this create a chip and add it in XML with match_parent in both width and height it will take the whole space of the parent and now add it programmatically it will take the space of the content inside it. you have to set width and height programmatically.