View Binding is Google’s View Binding component. After starting View Binding, the system automatically generates a corresponding Binding class for each XML layout file we add. An instance of the binding class contains direct references to all views that have ids in the corresponding layout. The following article will introduce the application and analysis principle.

Note: View Binding is only available on Android Studio3.6 Canary 11 and later

A: rely on

Add the following to your app’s build.gradle file:

android {
    ...
    buildFeatures {
        viewBinding true}}Copy the code

The XxxBinding class is automatically generated based on the layout file

Create a layout and recompile it, such as an activity_main.xml layout file. The system automatically generates datA_binding_base_class_source_out ->debug->out-> package name ->databinding An activityMainbinding. Java file is automatically created under. The activityMainbinding. Java file was named after activity_main was renamed as a header. The code is as follows:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.activity.MainActivity">

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:gravity="center"
        android:text="Hello World!"
        android:textColor="@color/colorPrimary"
        android:textSize="15sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_commit"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:text="Complete"
        android:textSize="15sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_name" />

    <FrameLayout
        android:id="@+id/layout_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_commit" />

</androidx.constraintlayout.widget.ConstraintLayout>
Copy the code

Layout in the outermost layer is ConstraintLayout, containing the View has a TextView, Button, FramLayout. Look at the code for the corresponding automatically generated ActivityMainBinding.java class

public final class ActivityMainBinding implements ViewBinding {
  @NonNull
  private final ConstraintLayout rootView;

  @NonNull
  public final Button btnCommit;

  @NonNull
  public final FrameLayout layoutContent;

  @NonNull
  public final TextView tvName;

  private ActivityMainBinding(@NonNull ConstraintLayout rootView, @NonNull Button btnCommit,
      @NonNull FrameLayout layoutContent, @NonNull TextView tvName) {
    this.rootView = rootView;
    this.btnCommit = btnCommit;
    this.layoutContent = layoutContent;
    this.tvName = tvName;
  }

  @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: {
      Button btnCommit = rootView.findViewById(R.id.btn_commit);
      if (btnCommit == null) {
        missingId = "btnCommit";
        break missingId;
      }
      FrameLayout layoutContent = rootView.findViewById(R.id.layout_content);
      if (layoutContent == null) {
        missingId = "layoutContent";
        break missingId;
      }
      TextView tvName = rootView.findViewById(R.id.tv_name);
      if (tvName == null) {
        missingId = "tvName";
        break missingId;
      }
      return new ActivityMainBinding((ConstraintLayout) rootView, btnCommit, layoutContent, tvName);
    }
    throw new NullPointerException("Missing required view with ID: ".concat(missingId)); }}Copy the code
  • The four member variables in the ActivityMainBinding correspond to the four Views in the layout file activity_main.xml
  • The constructor for ActivityMainBinding passes in four controls
  • The outermost control returned by the getRoot() method of ActivityMainBinding
  • The inflate method for the ActivityMainBinding is View root = inflater.inflate(R.layout.activity_main, parent, false); Create a View based on the Activity_main layout and call bind
  • The Bind method for ActivityMainBinding is fingViewById binding and generates an ActivityMainBinding instance

Use XXXBinding in your Activity

We have already generated the ActivitMainBinding class. Let’s see how we can use it in MainActivity as follows:

class MainActivity : AppCompatActivity() ,View.OnClickListener{

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.tvName.text = "View Binding Text"
        binding.btnCommit.text = "View Binding Btn"
        binding.btnCommit.setOnClickListener(this)

        supportFragmentManager.beginTransaction().replace(R.id.layout_content,LoginFragment()).commitAllowingStateLoss()

    }

    override fun onClick(v: View?). {
        when(v){
            binding.btnCommit-> Toast.makeText(this."click btn",Toast.LENGTH_SHORT).show()
        }
    }
}
Copy the code
  • Binding = ActivityMainBinding. Inflate (layoutInflater) based on the above analysis we ActivityMainBinding source code of a class, You can see that the inflate method creates the View according to activity_main.xml and passes the generated View through the constructor to an ActivityMainBinding, which creates an ActivityMainBinding instance
  • SetContentView (binding.root) uses the outermost layer of the binding as the contentView
  • BtnCommit, binding.tvName, binding.btnCommit, then you can use the view inside the binding

4. Use in fragments

Create a new fragment_login. XML layout

// Fragment_login. XML has the following layout<? xml version="1.0" encoding="utf-8"? > <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btn_login"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:gravity="center"
        android:text="Login"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
Copy the code

The recompilation will automatically generate the FragmentMainBinding class for us

// The corresponding automatically generated FragmentLoginBinding class
public final class FragmentLoginBinding implements ViewBinding {
  @NonNull
  private final ConstraintLayout rootView;

  @NonNull
  public final Button btnLogin;

  private FragmentLoginBinding(@NonNull ConstraintLayout rootView, @NonNull Button btnLogin) {
    this.rootView = rootView;
    this.btnLogin = btnLogin;
  }

  @Override
  @NonNull
  public ConstraintLayout getRoot() {
    return rootView;
  }

  @NonNull
  public static FragmentLoginBinding inflate(@NonNull LayoutInflater inflater) {
    return inflate(inflater, null.false);
  }

  @NonNull
  public static FragmentLoginBinding inflate(@NonNull LayoutInflater inflater,
      @Nullable ViewGroup parent, boolean attachToParent) {
    View root = inflater.inflate(R.layout.fragment_login, parent, false);
    if (attachToParent) {
      parent.addView(root);
    }
    return bind(root);
  }

  @NonNull
  public static FragmentLoginBinding 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: {
      Button btnLogin = rootView.findViewById(R.id.btn_login);
      if (btnLogin == null) {
        missingId = "btnLogin";
        break missingId;
      }
      return new FragmentLoginBinding((ConstraintLayout) rootView, btnLogin);
    }
    throw new NullPointerException("Missing required view with ID: ".concat(missingId)); }}Copy the code

Use the following in Fragment:

class LoginFragment :Fragment(),View.OnClickListener{

    private varloginBinding:FragmentLoginBinding? =null

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup? , savedInstanceState:Bundle?).: View? {
        loginBinding = FragmentLoginBinding.inflate(inflater,container,false)
        returnloginBinding? .root }override fun onActivityCreated(savedInstanceState: Bundle?). {
        super.onActivityCreated(savedInstanceState) loginBinding? .btnLogin? .text ="Login completed"loginBinding? .btnLogin? .setOnClickListener(this)}override fun onClick(v: View?). {
        when(v){ loginBinding? .btnLogin-> Toast.makeText(activity,"click login btn", Toast.LENGTH_SHORT).show()
        }
    }

    override fun onDestroyView(a) {
        loginBinding = null
        super.onDestroyView()
    }
}
Copy the code

We created a new fragment_login. XML layout, which will automatically generate the FragmentLoginBinding class to use in the Fragment. Call in onCreateView FragmentLoginBinding. Inflate (inflater, container, false), and return the outermost layers of the loginBinding layout. Null loginBinding in onDestroyView.

No Binding class configuration is generated

As we mentioned above, creating a new layout and recompiling it will automatically create the corresponding Binding class for us if we don’t want to. Just add tools to the layout :viewBindingIgnore=”true”. The code is as follows:

<FrameLayout
   tools:viewBindingIgnore="true">
</FrameLayout>
Copy the code