ViewBinding as a replacement
TLDR;
ViewBinding is a new clean replacement for findViewById with null and type-safety and it’s not a replacement for DataBinding.
Yesterday was the last day of 2019 and it was a year full of new things in the Software Development World generally and in the Android Development World specifically and one of these things is ViewBinding, it was first announced at Google I/O event as a new way of accessing your XML layouts, so let’s start with knowing what is it
What is ViewBinding?
View binding is a feature that allows you to more easily 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.
As the documentation says, view binding allows you to access views from XML and handle what you want to do with them, that’s basically what findViewById does, what is the difference then? well, it comes with 2 important advantages;
Type safety:
You won’t have any risk of ClassCastException as the fields in the generated binding class will have types matching the views they reference in the XML file.
Null safety:
You won’t have any risk of NullPointerException due to an invalid ID either as view binding creates direct references to views, in case of multiple configurations with multiple layouts, a tablet for example, and your view is presented in only one layout of them it will be annotated with @Nullable as it might be null in this case.
All of this and the idea itself behind ViewBinding as it declares fields for your view in the generated classes make it a clean, safe and compile-time replacement for findViewById, now let’s get through an example.
Using ViewBinding
First, we need to know that View binding is available in Android Studio 3.6 Canary 11, this example works the same for a fragment, let’s get Started
Let the Gradle knows that we will be working with ViewBinding to, by doing that ViewBinding will generate a binding class for every XML layout, this generated class will follow PascalCase suffixed with Binding work, for example, if our XML file is activity_main it will be ActivityMainBinding.
android { ... viewBinding { enabled = true } }
Then make sure that your view has an id to be able to access it
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android" xmlns:app="https://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/hello_world_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
ViewBinding will generate the binding class for you, like this:
import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.viewbinding.ViewBinding; import com.abadyyy.side_project.viewbindingtest.R; import java.lang.NullPointerException; import java.lang.Override; import java.lang.String; public final class ActivityMainBinding implements ViewBinding { @NonNull private final ConstraintLayout rootView; @NonNull public final TextView helloWorldTv; private ActivityMainBinding(@NonNull ConstraintLayout rootView, @NonNull TextView helloWorldTv) { this.rootView = rootView; this.helloWorldTv = helloWorldTv; } @Override @NonNull public ConstraintLayout getRoot() { return rootView; } @NonNull public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater) { return inflate(inflater, null, false); } @NonNull public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater, @Nullable ViewGroup parent, boolean attachToParent) { View root = inflater.inflate(R.layout.activity_main, parent, false); if (attachToParent) { parent.addView(root); } return bind(root); } @NonNull public static ActivityMainBinding bind(@NonNull View rootView) { // The body of this method is generated in a way you would not otherwise write. // This is done to optimize the compiled bytecode for size and performance. String missingId; missingId: { TextView helloWorldTv = rootView.findViewById(R.id.hello_world_tv); if (helloWorldTv == null) { missingId = "helloWorldTv"; break missingId; } return new ActivityMainBinding((ConstraintLayout) rootView, helloWorldTv); } throw new NullPointerException("Missing required view with ID: ".concat(missingId)); }}
Now we have to tell our Activity that we will be using the root of that generated binding instead of the ordinary XML reference, now you can access any view as a field from that binding variable and they will be named following camelCase convention.
class MainActivity : AppCompatActivity() { private lateinit var mainBinding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mainBinding = ActivityMainBinding.inflate(layoutInflater) setContentView(mainBinding.root) // Now you can access any view from that xml following a camelCase convention without the underscores. mainBinding.helloWorldTv.text = "Hello ViewBinding" } }
NOTE: you can disable the generation of the binding class for any particular XML file by adding this attribute, tools:viewBindingIgnore="true", to your layout parent element.
Can ViewBinding replace DataBinding?
Sharing half of the name doesn’t mean necessarily that they can replace each other, ViewBinding is intended to be a clean replacement for findViewById not more than that and it’s not a replacement for DataBinding and if you feel like it can fit in your case then you are probably using DataBinding wrong and I strongly advise you not to do that as it has a lot of pitfalls and many things to take care of, will be talking about them in another article soon.
Thanks for reading! Be sure to like below and recommend this article if you liked it.
Reach me out on Twitter, Medium