It is often said that programmers are lazy and that (usually) is a good thing. It means that instead of repeating tasks or code, programmers often find ways to avoid having to do that over and over time. Android developers have for years tried to avoid boiler plate code related to findViewById
. Imagine we have a layout like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/mainTitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" android:gravity="center" android:padding="16dp" android:textSize="18sp" tools:text="Main Title" /> <TextView android:id="@+id/subTitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/mainTitle" android:gravity="center" android:padding="16dp" android:textSize="14sp" tools:text="Main Subtitle" /> </RelativeLayout> |
When we need to access the above views and use them in Java code, we usually do the same thing as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class MainActivity extends AppCompatActivity { private TextView txtViewMainTitle; private TextView txtViewSubTitle; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtViewMainTitle = findViewById(R.id.mainTitle; txtViewSubTitle = findViewById(R.id.subTitle); txtViewMainTitle.setText("This is my main title"); txtViewSubTitle.setText("This is my subTitle"); } } |
It looks familiar, right?
findViewById – “the old way”
In order to avoid these boiler plate code, many programmers started using the Butter Knife library, or older RoboGuice (a Dependency injection framework that allows us to inject views, which is no longer supported). . Butter Knife is still used in many applications and its GitHub is still active. However, library development will probably stop soon. If you have used Kotlin in your application, you have probably used Kotlin Android Extensions . The libraries mentioned above require an annotation field for each expose view. Kotlin Android Extensions are much easier to use, because they allow us to use the same results from the libraries without having to add any code. For example:
1 2 3 4 5 6 7 8 9 10 11 12 | import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mainTitle.text = "This is my main title" subTitle.text = "This is my subTitle" } } |
Accessing views looks a lot simpler. However, with ViewBinding, things are even better.
findViewById – “the new (cool?) way”
ViewBinding introduced at [Google I / O 19] ( https://youtu.be/td3Kd7fOROw?t=1756 Preview) offers a faster, simpler, type / null safe to bind views. At the moment, it is still an experimental feature and only available on Android Studio 3.6 Canary 11+ After downloading and installing Android Studio Canary, to be able to use ViewBinding, we need to enable it in the build.grade
file. :
1 2 3 4 5 6 7 | android { ... viewBinding { enabled = true } } |
Although the official documentation does not mention, we also need to upgrade Android Studio Gradle Plugin to version 3.6.0-alpha11
or higher.
1 2 3 4 5 6 7 8 9 10 11 12 13 | buildscript { ext.kotlin_version = '1.3.50' repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.6.0-alpha12' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } |
Note that the version of Gradle used needs to be 5.6.1
or higher. Take a look at the gradle-wrapper.properties
file and check that the version of Gradle is guaranteed. After that, we were able to use ViewBinding. Let’s continue looking at the previous example, when using ViewBinding, our code will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.mainTitle.text = "This is my main title" binding.subTitle.text = "This is my subTitle" } } |
The name of the binding class is generated by converting the name of the XML file to a camel case type and adding the “Binding” suffix. Therefore, in this case its name is ActivityMainBinding
. The ActivityMainBinding
class has two fields: one TextView
called mainTitle
and another TextView
named subTitle
. Any view in the layout file that is not assigned an id will not be referenced in the class binding. To gain access to the root view of the layout file, each binding class will include a getRoot()
. In this example, the getRoot()
of ActivityMainBinding
will return a RelativeLayout
. The created binding class contains a static method ActivityMainBinding.inflate(LayoutInflater)
that allows to create an instance of the class. Basically, what it does is inflate the entire layout hierarchy to access the views. Then we just need to call the setContentView
method and pass it to the root
view to create that view on the screen.
Advantages
The ViewBinding feature has several advantages when compared to a traditional approach as well as when compared to a few other libraries: *** Null safety: ** view binding creates a direct reference to views, because There is no possibility of a NullPointerException
happening due to an invalid view ID. Also, when a view only exists under certain conditions, the field containing its reference in the binding class will be marked with the @Nullable
annotation. *** Type safety: ** all view binding fields are generater match of the same type as its reference in XML, so there is no need to cast. That means the risk of ClassCastException
will be lower. In case if the layout and code do not match for some reason, the build will fail at compile time instead of at runtime. *** Speed: ** ViewBinding requires no additional build time as it does not use annotation processor like ButterKnife or DataBinding.
ViewBinding vs DataBinding
At this point, you’re probably wondering if ViewBinding and DataBinding are the same? Both generate class binding so that we can use references to the view directly, but there are some differences.
- To use DataBinding we need to add the
layout
tag to thelayout
XML file. - ViewBinding does not support layout variable or layout expression.
Summary
Above is a little introduction to ViewBinding . Hope to bring useful knowledge to everyone. Thanks for taking the time to read your article. References: