美文网首页
Android Jetpack ViewBinding

Android Jetpack ViewBinding

作者: 遇见的延长线 | 来源:发表于2021-04-16 16:22 被阅读0次

    ViewBinding(视图绑定)
    通过ViewBinding,可以更轻松地编写可与视图交互的代码。在模块中启用ViewBinding后,系统会为该模块中的每个XML布局文件生成一个绑定类。绑定类的实例包含对在相应布局中具有ID的所有视图的直接引用。多数情况下ViewBinding会替换掉findViewById。开启方式有如下两种方式:

        //方式一  
        viewBinding{
          enabled=true
        }
        //方式二 
        buildFeatures {
            viewBinding true
        }
    

    如果希望在生成绑定类的时候忽略某个布局文件,可以在布局文件的根目录上添加tools:viewBindingIgnore="true"属性。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 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"
        android:orientation="vertical"
        tools:viewBindingIgnore="true">
    
    </LinearLayout>
    

    模块开启视图绑定功能后,系统会为该模块中包含的每个XML布局文件生成一个绑定类。每个绑定类均包含对根View以及布局中具有ID的所有视图的引用。系统生成绑定类的命名方式是:通过将XML文件的名称去下划线后转换成驼峰式大小写并在末尾添加"Binding"的方式。例如 activity_main.xml 会生成一个ActivityMainBinding的视图绑定类。如下为activity_main.xml文件的内容

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 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"
        android:orientation="vertical">
    
        <TextView
            android:id="@+id/name_view"
            android:layout_width="match_parent"
            android:layout_height="46dp"
            android:gravity="center"
            android:text="@string/app_name" />
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="46dp"
            android:gravity="center"
            android:text="ceshi" />
    
        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="46dp"
            android:text="确定" />
    </LinearLayout>
    

    此XML布局文件对应的ActivityMainBinding类,包含了对根视图的引用及具有ID 的View的引用,通过绑定类 具体实例的getRoot()方法来获取根视图的引用,视图中具有ID的view则会在绑定类中生成相应ID名称对应的字段,如此视图中的"name_view"和"button"这两个view会在绑定类中生成nameView 和button两个字段(字段生成规则为去下划线后改驼峰式大小写命名)。具体生成的绑定类如下:

    // Generated by view binder compiler. Do not edit!
    package com.gexing.test.databinding;
    
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Button;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;
    import androidx.viewbinding.ViewBinding;
    import com.gexing.test.R;
    import java.lang.NullPointerException;
    import java.lang.Override;
    import java.lang.String;
    
    public final class ActivityMainBinding implements ViewBinding {
      @NonNull
      private final LinearLayout rootView;
    
      @NonNull
      public final Button button;
    
      @NonNull
      public final TextView nameView;
    
      private ActivityMainBinding(@NonNull LinearLayout rootView, @NonNull Button button,
          @NonNull TextView nameView) {
        this.rootView = rootView;
        this.button = button;
        this.nameView = nameView;
      }
    
      @Override
      @NonNull
      public LinearLayout 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.
        int id;
        missingId: {
          id = R.id.button;
          Button button = rootView.findViewById(id);
          if (button == null) {
            break missingId;
          }
    
          id = R.id.name_view;
          TextView nameView = rootView.findViewById(id);
          if (nameView == null) {
            break missingId;
          }
    
          return new ActivityMainBinding((LinearLayout) rootView, button, nameView);
        }
        String missingId = rootView.getResources().getResourceName(id);
        throw new NullPointerException("Missing required view with ID: ".concat(missingId));
      }
    }
    
    

    ViewBinding如何在Activity和Fragment中使用:
    上述绑定类中 我们发现有多个静态类方法:

    1.ActivityMainBinding inflate(@NonNull LayoutInflater inflater)
    2.public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater,
    @Nullable ViewGroup parent, boolean attachToParent)
    3.public static ActivityMainBinding bind(@NonNull View rootView)
    这三个静态方法的返回值都式绑定类类型的实例,通过这个实例我们便可以获取到相应的rootView 由此便可以在activity和fragment中使用。

    在Activity中使用:直接在onCreate方法中替换原有的setContentView(R.layout.activity_main)的方式

    package com.gexing.test
    
    import android.os.Bundle
    import androidx.appcompat.app.AppCompatActivity
    import com.gexing.test.databinding.ActivityMainBinding
    
    class MainActivity : AppCompatActivity() {
        lateinit var mainBinding: ActivityMainBinding
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    //        setContentView(R.layout.activity_main)
            mainBinding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(mainBinding.root)
        }
    }
    

    在Fragment中使用:在onCreateView方法中处理

    package com.gexing.test
    
    import android.os.Bundle
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import androidx.fragment.app.Fragment
    import com.gexing.test.databinding.ActivityMainBinding
    
    class TestFragment : Fragment() {
        var mainBinding: ActivityMainBinding? = null
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            mainBinding = mainBinding ?: ActivityMainBinding.inflate(inflater, container, false)
            return mainBinding?.root
        }
    }
    override fun onDestroyView() {
            super.onDestroyView()
            mainBinding = null
        }
    

    ViewBinding与普通findViewById的区别:

    1.Null安全,由于ViewBinding会创建对视图的直接引用,因此不存在因视图ID无效而引发的Null指针异常的风险。此外如果视图仅出现在布局的某些配置中,则绑定类中包含其引用的字段会使用@Nullable标记。
    2.类型安全每个绑定类中的字段均具有与它们XML文件中引用的View相匹配的类型,这意味着不存在类转换异常的风险。
    这些差异意味着布局和代码之间的不兼容将会导致构建在编译时失败,而非在运行时出现异常。

    相关文章

      网友评论

          本文标题:Android Jetpack ViewBinding

          本文链接:https://www.haomeiwen.com/subject/uocelltx.html