This paper sketches

  • In build.gradle, you can easily and quickly start view binding without introducing additional dependency libraries

  • View the binding will be generated for each of the Module layout file a binding object (activity_awesome. XML – > ActivityAwesomeBinding. Java)

  • Each view with an ID in the layout file will have a corresponding property in the binding object, which will have the correct type and be null safe

  • View binding supports Java and Kotlin programming languages perfectly

Tencent Video link:

V.qq.com/x/page/h093…

Bilibili video link:

www.bilibili.com/video/av953…

Enable view binding in build.gradle

Starting with Android Studio 3.6, view binding will be built into the Android Gradle plugin. To enable viewBinding, simply configure the viewBinding option in the build.gradle file:

Android {viewBinding {enabled =true}}Copy the code

In Android Studio 4.0, viewBinding becomes a property that is incorporated into the buildFeatures option, so the configuration is changed to:

// Android Studio 4.0 Android {buildFeatures {viewBinding =true}}Copy the code

Once configured, view binding automatically generates binding classes for all layout files. Instead of modifying the XML file for the original layout, the view binding will do all the work automatically based on your existing layout.

View bindings will generate binding objects for all layout files in the Module based on the existing XML file.

You can use bound objects anywhere you need to fill a layout, such as fragments, activities, or even the RecyclerView Adapter (or ViewHolder).

Use view bindings in your Activity

Suppose you have a layout file called activity_awesome. XML that contains a button and two text views. View binding generates a class called ActivityAwesomeBinding for the layout. All views in the layout file that have ids will have a property in this class:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val binding = ActivityAwesomeBinding.inflate(layoutInflater)

    binding.title.text = "Hello"
    binding.subtext.text = "Concise, safe code"
    binding.button.setOnClickListener { /* ... */ }

    setContentView(binding.root)
}
Copy the code

△ Use view binding in an Activity

With view binding, you no longer need to call the findViewById method, but simply call the corresponding property in the binding object directly.

The root view of the layout (with or without an ID) automatically generates an attribute named root. In the Activity’s onCreate method, pass root to the setContentView method, allowing the Activity to use the layout in the bound object.

A common mistake is to use setContentView(…) with view binding enabled. Pass in the id of the layout instead of the binding object. This causes the same layout to be populated twice and listeners to be added to the wrong layout object.

Solution: When using view binding in an Activity, be sure to pass the root property of the bound object into the setContentView() method.

Use binding objects to write more secure code

FindViewById is the source of many user-visible bugs: it’s easy to pass in an ID that doesn’t exist in the layout and crash with a null pointer exception; Because this method is type-insecure, it’s easy to write code like findViewById(R.I.D.Mage) that causes cast errors. To address these issues, the view binding replaces findViewById with a more concise and secure implementation.

View binding has the following two features:

  • Type-safe: Because view bindings always generate property-type properties based on views in the layout. So if you put a TextView in the layout, the view binding will expose a property of type TextView to you. Null security: The view binding detects if a view exists only under certain configurations and generates properties with @Nullable annotations based on the results. So even with layout files defined in multiple configurations, view bindings can remain null safe.

  • Since the generated binding classes are normal Java classes with kotlin-friendly annotations, view bindings can be used by both Java and Kotlin.

What is the code generated by the view binding

As mentioned earlier, the view binding generates a Java class that contains the alternative findViewById functionality. It will be for each layout under the Module XML file to generate a corresponding binding object, and according to the source file for its name, such as activity_awesome. The corresponding binding objects to XML ActivityAwesomeBinding. Java.

The logic for generating the code is optimized so that when you edit an XML layout file in Android Studio, only the binding objects corresponding to the modified layout are updated. At the same time, the work runs in memory, allowing the process to be completed quickly. This means that your changes are immediately reflected in the binding object, without having to wait or rebuild the project.

Android Studio is optimized to update binding objects as soon as you edit the XML layout file.

Let’s take a look at the code generated by a sample XML layout to see exactly what the view binding generates.


public final class ActivityAwesomeBinding implements ViewBinding {
  @NonNull
  private final ConstraintLayout rootView;
  @NonNull
  public final Button button;
  @NonNull
  public final TextView subtext;
  @NonNull
  public final TextView title;
Copy the code

△ Attributes generated by view binding. You can see that they are both type safe and empty safe

View bindings generate the right type of properties for each view that has an ID. It also generates the rootView property for the root layout and exposes it to you through getRoot. The view binding doesn’t add any additional logic; it just exposes the view properties to you so you can call them without using findViewById. This ensures that the generated files are concise (and, of course, avoid slowing down the build).

If you are using Kotlin, the generated classes for the view binding have also been optimized for interoperability. By using the @Nullable and @nonNULL annotations, Kolin correctly exposes properties as null-safe. To learn more about interoperability between the two languages, check out the documentation: Calling Java in Kotlin.

private ActivityAwesomeBinding(@NonNull ConstraintLayout rootView, @NonNull Button button, @NonNull TextView subtext, NonNull TextView title) {... } @nonnull public static ActivityAwesomeBinding Inflater (@nonnull LayoutInflater) {/* Uninflate (inflater, parent, attachToParent) call */ View root = Inflater.inflate (R.layout.activity_awesome, null,false);
    return bind(root);
  }
Copy the code

View bindings generate the inflate method as the main way to generate an instance of the bound object. In ActivityAwesomeBinding. In Java, and generates a view binding only inflate a parameter method, the method by the parent set to null to specify the current view will not bound to the parent view; View bindings also expose a inflate method with three arguments, allowing you to pass the parent and attachToParent arguments when needed.

The real magic is the call to the bind method. This will populate the view and bind all the properties, while doing some error checking and generating a clear error message.


@NonNull
 public static ActivityAwesomeBinding bind(@nonnull View rootView) {/* Edit: simplify the code -- in real life the generated code is an optimized version */ Button Button = RootView.findViewById (R.I. D.Botton); TextView subtext = rootView.findViewById(R.id.subtext); TextView title = rootView.findViewById(R.id.title);if(button ! = null && subtext ! = null && title ! = null) {return new ActivityAwesomeBinding((ConstraintLayout) rootView, button, subtext, title);
   }
   throw new NullPointerException("Missing the required view [...]. ");
 }
Copy the code

A simplified version of the automatically generated bind method

Bind, the most complex method of binding objects, binds each view by calling findViewById. Since the compiler knows the type and nullability of each attribute from the XML layout file, it can safely call findViewById.

Note that the real bind method generated by the view binding is much longer and uses a markup break statement to optimize the bytecode. You can check out this article by Jake Wharton for more on optimization. Within each binding object, there are three static methods exposed to create instances of the binding object. Here is a brief description of the usage scenarios for each method:

  • Inflate (inflater) — This class is used in cases where no superview needs to be passed, such as in the Activity onCreate method

  • Inflate (inflater, parent, attachToParent) — in the Fragment or RecyclerView Adapter (or ViewHolder), This is used when you need to pass the parent ViewGroup to the bound object.

  • Bind (rootView) — used when you already have the corresponding view and just want to avoid using findViewById by binding the view. This approach is useful when modifying and refactoring existing code using view bindings.

    • Sample XML layout gist.github.com/objcode/3ee…
    • Kotlin invokes the Java kotlinlang.org/docs/refere…
    • Jake Wharton wrote this article jakewharton.com/optimizing-…

What happens to layouts introduced using include tags

As mentioned earlier, view bindings generate a binding object for each layout file in a Module. This is also true if the layout file is included in another layout file.

<! -- activity_awesome.xml --> <androidx.constraintlayout.widget.ConstraintLayout> <include android:id="@+id/includes" layout="@layout/included_buttons"</androidx.constraintlayout.widget.ConstraintLayout> <! -- included_buttons.xml --> <androidx.constraintlayout.widget.ConstraintLayout> <Button android:id="@+id/include_me" />
</androidx.constraintlayout.widget.ConstraintLayout>
Copy the code

Note: There is an ID under the include tag.

When using an imported layout, the view binding creates a reference to the imported layout binding object. Note that the include> tag has an ID: Android :id=”@+id/includes”. The logic here is the same as using a normal view. Include tags need to have an ID to generate the corresponding attribute in the bound object.

Include tags must have an ID in order to generate attributes.


 public final class ActivityAwesomeBinding implements ViewBinding {
  ...

  @NonNull
  public final IncludedButtonsBinding includes;
Copy the code

The view binding generates a reference to the IncludedButtonsBinding in the ActivityAwesomeBinding.

Use view binding in conjunction with data binding

View binding is just an alternative to findViewById, and if you want to automatically bind views in XML, you can use the data binding library. Data binding and view binding can generate the same components, and they can work together.

When both are turned on, the layout using the label is generated by the data binding to the binding object; The rest of the layout generates binding objects from view bindings.

You can use both data binding and view binding in the same Module.

We developed view binding as a complement to data binding because many developers reported that they wanted a lightweight alternative to findViewById in addition to data binding — which view binding provides.

View binding compares the Kotlin synthesis method with ButterKnife

One of the most common questions about view binding is: “Should I use view binding instead of Kotlin synthesis or ButterKnife? “Both are very successful component libraries today, and many applications use them to solve findViewById problems.

For most applications, we recommend trying to replace these two libraries with view bindings, which provide a more secure and accurate way to map views.

View binding is null safe, only references views in the current layout, supports Java and Kotlin, and is more concise

The figure above compares the functionality of the view binding, ButterKnife, and Kotlin synthesis methods.

While ButterKnife verifies nullable and non-nullable at run time, the compiler does not check whether the view you match exists in your layout.

For security and cleaner code, we recommend trying view binding.

Click here to learn more about view binding