当前位置:   article > 正文

ViewBinding(视图绑定)基础详解

viewbinding

一.简介

ViewBinding是Android Studio 3.6推出的新特性,旨在替代findViewById(内部实现还是使用findViewById)。通过ViewBinding,可以更轻松地编写可与视图交互的代码。在模块中启用ViewBinding之后,系统会为该模块中的每个 XML 布局文件生成一个绑定类。绑定类的实例包含对在相应布局中具有 ID 的所有视图的直接引用。

注:ViewBinding&DataBinding区别

1.两者都生成可用于直接引用视图的绑定类。

2.View binding旨在处理更简单的用例,有以下特点

<1> 更快的编译: 视图绑定不需要注释处理,因此编译时间更快。

<2> 易用性: 视图绑定不需要特别标记的 XML 布局文件,因此在您的应用程序中采用它的速度更快。在模块中启用视图绑定后,它会自动应用于该模块的所有布局。

<3> 视图绑定不支持布局变量或布局表达式,因此它不能用于直接从 XML 布局文件声明动态 UI 内容。

3.DataBinding可以支持变量刷新,布局表达式,可以直接从 XML 布局文件声明动态 UI 内容。

二.依赖及文件路径

1.添加依赖 

模块build.gradle文件android节点下添加如下代码

  1. android {
  2. viewBinding{
  3. enabled = true
  4. }
  5. }

在 Android Studio 4.0 中,viewBinding 变成属性被整合到了 buildFeatures 选项中,所以配置要改成

  1. android {
  2. buildFeatures {
  3. viewBinding = true
  4. }
  5. }

2.文件路径

配置好上述Gradle,成功编译后,在相应Module中对应的文件夹下回看到生成的内容

三.Activity使用

1.Activity代码

  1. public class BaseModuleMainActivity extends AppCompatActivity {
  2. ActivityBaseModuleMainBinding binding;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. binding = ActivityBaseModuleMainBinding.inflate(getLayoutInflater());
  7. setContentView(binding.getRoot());
  8. binding.tvBaseModule.setText("我是TextView");
  9. binding.tvBaseModule.setOnClickListener(v -> LoggerUtils.logD("BaseModuleMainActivity", "TextView点击..."));
  10. }
  11. }

2.Activity布局

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent">
  6. <TextView
  7. android:id="@+id/tv_base_module"
  8. android:layout_width="match_parent"
  9. android:layout_height="@dimen/dp_100"
  10. android:background="@color/purple_200"
  11. android:gravity="center"
  12. android:textColor="@color/white"
  13. tools:ignore="MissingConstraints" />
  14. </androidx.constraintlayout.widget.ConstraintLayout>

3.结果

BaseModuleMainActivity  TextView点击...

4.说明

原本默认情况下Activity的onCreate方法是这样的

  1. @Override
  2. protected void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. setContentView(R.layout.activity_main);
  5. ...
  6. }

即,使用setContentView()方法设置布局。而使用ViewBinding则需要在setContentView()方法前获取XXXBinding对象。

binding = ActivityBaseModuleMainBinding.inflate(getLayoutInflater());

然后调用XXXBinding对象的getRoot方法获取XXXView设置到setContentView()方法。

setContentView(binding.getRoot());

5.源码

生成的XXXBinding文件是按照Activity布局的名称驼峰生成的。

比如上述我们的Activity布局名称是activity_base_module_main

那么生成的Binding文件名称则是ActivityBaseModuleMainBinding。

  1. public final class ActivityBaseModuleMainBinding implements ViewBinding {
  2. @NonNull
  3. private final ConstraintLayout rootView;
  4. @NonNull
  5. public final TextView tvBaseModule;
  6. private ActivityBaseModuleMainBinding(@NonNull ConstraintLayout rootView,
  7. @NonNull TextView tvBaseModule) {
  8. this.rootView = rootView;
  9. this.tvBaseModule = tvBaseModule;
  10. }
  11. @Override
  12. @NonNull
  13. public ConstraintLayout getRoot() {
  14. return rootView;
  15. }
  16. @NonNull
  17. public static ActivityBaseModuleMainBinding inflate(@NonNull LayoutInflater inflater) {
  18. return inflate(inflater, null, false);
  19. }
  20. @NonNull
  21. public static ActivityBaseModuleMainBinding inflate(@NonNull LayoutInflater inflater,
  22. @Nullable ViewGroup parent, boolean attachToParent) {
  23. View root = inflater.inflate(R.layout.activity_base_module_main, parent, false);
  24. if (attachToParent) {
  25. parent.addView(root);
  26. }
  27. return bind(root);
  28. }
  29. @NonNull
  30. public static ActivityBaseModuleMainBinding bind(@NonNull View rootView) {
  31. // The body of this method is generated in a way you would not otherwise write.
  32. // This is done to optimize the compiled bytecode for size and performance.
  33. int id;
  34. missingId: {
  35. id = R.id.tv_base_module;
  36. TextView tvBaseModule = rootView.findViewById(id);
  37. if (tvBaseModule == null) {
  38. break missingId;
  39. }
  40. return new ActivityBaseModuleMainBinding((ConstraintLayout) rootView, tvBaseModule);
  41. }
  42. String missingId = rootView.getResources().getResourceName(id);
  43. throw new NullPointerException("Missing required view with ID: ".concat(missingId));
  44. }
  45. }

四.Fragment使用

1.Fragment代码

  1. public class BaseModuleMainFragment extends Fragment {
  2. FragmentBaseModuleMainBinding binding;
  3. @Override
  4. public void onCreate(@Nullable Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. LoggerUtils.logD("BaseModuleMainFragment", "onCreate方法执行...");
  7. }
  8. @Nullable
  9. @Override
  10. public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
  11. binding = FragmentBaseModuleMainBinding.inflate(inflater, container, false);
  12. LoggerUtils.logD("BaseModuleMainFragment", "onCreateView方法执行...");
  13. return binding.getRoot();
  14. }
  15. @Override
  16. public void onViewCreated(@NonNull View view, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
  17. super.onViewCreated(view, savedInstanceState);
  18. binding.tv01.setText("我是textView");
  19. binding.tv01.setOnClickListener(v -> LoggerUtils.logD("BaseModuleMainFragment", "TextView点击..."));
  20. binding.btn01.setText("我是Button");
  21. binding.btn01.setOnClickListener(v -> LoggerUtils.logD("BaseModuleMainFragment", "Button点击..."));
  22. LoggerUtils.logD("BaseModuleMainFragment", "onViewCreated方法执行...");
  23. }
  24. }

2.Fragment布局

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. xmlns:app="http://schemas.android.com/apk/res-auto">
  7. <TextView
  8. android:id="@+id/tv_01"
  9. android:layout_width="match_parent"
  10. android:layout_height="@dimen/dp_100"
  11. android:background="@color/purple_200"
  12. android:gravity="center"
  13. android:textColor="@color/white"
  14. tools:ignore="MissingConstraints" />
  15. <Button
  16. android:id="@+id/btn_01"
  17. android:layout_width="match_parent"
  18. android:layout_height="@dimen/dp_100"
  19. android:background="@color/purple_500"
  20. app:layout_constraintTop_toBottomOf="@+id/tv_01"
  21. android:layout_marginTop="10dp"
  22. android:gravity="center"
  23. android:textColor="@color/white"
  24. tools:ignore="MissingConstraints" />
  25. </androidx.constraintlayout.widget.ConstraintLayout>

3.结果

  1. ### 初始化打印内容 ###
  2. onCreate方法执行...
  3. onCreateView方法执行...
  4. onViewCreated方法执行...
  5. ### 点击TextView打印内容 ###
  6. TextView点击...
  7. ### 点击Button打印内容 ###
  8. Button点击...

4.说明

原本默认情况下Fragment的onCreateView方法是这样的

  1. @Nullable
  2. @Override
  3. public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
  4. View view = inflater.inflate(R.layout.fragment_base_module_main, container, false);
  5. initView(view);
  6. return view;
  7. }

使用ViewBinding后变成

  1. binding = FragmentBaseModuleMainBinding.inflate(inflater, container, false);
  2. return binding.getRoot();

5.源码

  1. public final class FragmentBaseModuleMainBinding implements ViewBinding {
  2. @NonNull
  3. private final ConstraintLayout rootView;
  4. @NonNull
  5. public final Button btn01;
  6. @NonNull
  7. public final TextView tv01;
  8. private FragmentBaseModuleMainBinding(@NonNull ConstraintLayout rootView, @NonNull Button btn01,
  9. @NonNull TextView tv01) {
  10. this.rootView = rootView;
  11. this.btn01 = btn01;
  12. this.tv01 = tv01;
  13. }
  14. @Override
  15. @NonNull
  16. public ConstraintLayout getRoot() {
  17. return rootView;
  18. }
  19. @NonNull
  20. public static FragmentBaseModuleMainBinding inflate(@NonNull LayoutInflater inflater) {
  21. return inflate(inflater, null, false);
  22. }
  23. @NonNull
  24. public static FragmentBaseModuleMainBinding inflate(@NonNull LayoutInflater inflater,
  25. @Nullable ViewGroup parent, boolean attachToParent) {
  26. View root = inflater.inflate(R.layout.fragment_base_module_main, parent, false);
  27. if (attachToParent) {
  28. parent.addView(root);
  29. }
  30. return bind(root);
  31. }
  32. @NonNull
  33. public static FragmentBaseModuleMainBinding bind(@NonNull View rootView) {
  34. // The body of this method is generated in a way you would not otherwise write.
  35. // This is done to optimize the compiled bytecode for size and performance.
  36. int id;
  37. missingId: {
  38. id = R.id.btn_01;
  39. Button btn01 = rootView.findViewById(id);
  40. if (btn01 == null) {
  41. break missingId;
  42. }
  43. id = R.id.tv_01;
  44. TextView tv01 = rootView.findViewById(id);
  45. if (tv01 == null) {
  46. break missingId;
  47. }
  48. return new FragmentBaseModuleMainBinding((ConstraintLayout) rootView, btn01, tv01);
  49. }
  50. String missingId = rootView.getResources().getResourceName(id);
  51. throw new NullPointerException("Missing required view with ID: ".concat(missingId));
  52. }
  53. }

五.Dialog使用

1.Dialog代码

  1. public class PrivacyAgreementDialog extends Dialog implements View.OnClickListener {
  2. private IDialogCallback mIDialogCallback;
  3. private DialogPrivacyagreementBinding binding;
  4. public PrivacyAgreementDialog(Activity activity) {
  5. super(activity, R.style.dialog_style);
  6. binding = DialogPrivacyagreementBinding.inflate(getLayoutInflater());
  7. }
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(binding.getRoot());
  12. binding.tvContent1.setText("内容1111");
  13. binding.tvContent2.setText("内容222");
  14. binding.tvCancel.setOnClickListener(this);
  15. binding.tvSure.setOnClickListener(this);
  16. setCancelable(false);//点击外部 对话框不消失
  17. }
  18. /**
  19. * 点击事件
  20. */
  21. @Override
  22. public void onClick(View v) {
  23. if (AntiShakeUtils.isInvalidClick(v)) return;
  24. if (v.getId() == R.id.tvCancel && null != mIDialogCallback) {
  25. mIDialogCallback.onCancelClick();
  26. } else if (v.getId() == R.id.tvSure && null != mIDialogCallback) {
  27. mIDialogCallback.onSureClick();
  28. }
  29. }
  30. /**
  31. * 设置回调监听
  32. */
  33. public void setDialogListener(IDialogCallback dialogListener) {
  34. mIDialogCallback = dialogListener;
  35. }
  36. }

2.布局代码

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. android:background="@color/transparent"
  7. android:gravity="center">
  8. <LinearLayout
  9. android:layout_width="match_parent"
  10. android:layout_height="wrap_content"
  11. android:layout_marginLeft="@dimen/dp_20"
  12. android:layout_marginRight="@dimen/dp_20"
  13. android:background="@drawable/drawable_while_bg_while_line_r3"
  14. android:orientation="vertical">
  15. <TextView
  16. android:id="@+id/tvTitle"
  17. android:layout_width="match_parent"
  18. android:layout_height="@dimen/dp_45"
  19. android:gravity="center"
  20. android:text="@string/privacy_agreement_textView01"
  21. android:textColor="#000000"
  22. android:textSize="@dimen/text_dp_14"
  23. tools:ignore="SpUsage" />
  24. <LinearLayout
  25. android:layout_width="match_parent"
  26. android:layout_height="wrap_content"
  27. android:layout_marginLeft="@dimen/dp_15"
  28. android:layout_marginTop="@dimen/dp_10"
  29. android:layout_marginRight="@dimen/dp_15"
  30. android:layout_marginBottom="@dimen/dp_10"
  31. android:orientation="vertical">
  32. <TextView
  33. android:id="@+id/tvContent1"
  34. android:layout_width="match_parent"
  35. android:layout_height="wrap_content"
  36. android:lineSpacingExtra="@dimen/dp_5"
  37. android:textColor="#FF37414E"
  38. android:textSize="@dimen/text_dp_14"
  39. tools:ignore="SpUsage" />
  40. <TextView
  41. android:id="@+id/tvContent2"
  42. android:layout_width="match_parent"
  43. android:layout_height="wrap_content"
  44. android:lineSpacingExtra="@dimen/dp_5"
  45. android:textColor="#FF37414E"
  46. android:textSize="@dimen/text_dp_14"
  47. tools:ignore="SpUsage" />
  48. </LinearLayout>
  49. <LinearLayout
  50. android:layout_width="match_parent"
  51. android:layout_height="@dimen/dp_45"
  52. android:orientation="horizontal"
  53. android:weightSum="2">
  54. <TextView
  55. android:id="@+id/tvCancel"
  56. android:layout_width="0dp"
  57. android:layout_height="match_parent"
  58. android:layout_weight="1"
  59. android:ellipsize="end"
  60. android:gravity="center"
  61. android:singleLine="true"
  62. android:text="@string/privacy_agreement_textView02"
  63. android:textColor="#FF37414E"
  64. android:textSize="@dimen/text_dp_14"
  65. tools:ignore="SpUsage" />
  66. <TextView
  67. android:id="@+id/tvSure"
  68. android:layout_width="0dp"
  69. android:layout_height="match_parent"
  70. android:layout_weight="1"
  71. android:ellipsize="end"
  72. android:gravity="center"
  73. android:singleLine="true"
  74. android:text="@string/privacy_agreement_textView03"
  75. android:textColor="#FF37414E"
  76. android:textSize="@dimen/text_dp_14"
  77. tools:ignore="SpUsage" />
  78. </LinearLayout>
  79. </LinearLayout>
  80. </LinearLayout>

3.源码

  1. public final class DialogPrivacyagreementBinding implements ViewBinding {
  2. @NonNull
  3. private final LinearLayout rootView;
  4. @NonNull
  5. public final TextView tvCancel;
  6. @NonNull
  7. public final TextView tvContent1;
  8. @NonNull
  9. public final TextView tvContent2;
  10. @NonNull
  11. public final TextView tvSure;
  12. @NonNull
  13. public final TextView tvTitle;
  14. private DialogPrivacyagreementBinding(@NonNull LinearLayout rootView, @NonNull TextView tvCancel,
  15. @NonNull TextView tvContent1, @NonNull TextView tvContent2, @NonNull TextView tvSure,
  16. @NonNull TextView tvTitle) {
  17. this.rootView = rootView;
  18. this.tvCancel = tvCancel;
  19. this.tvContent1 = tvContent1;
  20. this.tvContent2 = tvContent2;
  21. this.tvSure = tvSure;
  22. this.tvTitle = tvTitle;
  23. }
  24. @Override
  25. @NonNull
  26. public LinearLayout getRoot() {
  27. return rootView;
  28. }
  29. @NonNull
  30. public static DialogPrivacyagreementBinding inflate(@NonNull LayoutInflater inflater) {
  31. return inflate(inflater, null, false);
  32. }
  33. @NonNull
  34. public static DialogPrivacyagreementBinding inflate(@NonNull LayoutInflater inflater,
  35. @Nullable ViewGroup parent, boolean attachToParent) {
  36. View root = inflater.inflate(R.layout.dialog_privacyagreement, parent, false);
  37. if (attachToParent) {
  38. parent.addView(root);
  39. }
  40. return bind(root);
  41. }
  42. @NonNull
  43. public static DialogPrivacyagreementBinding bind(@NonNull View rootView) {
  44. // The body of this method is generated in a way you would not otherwise write.
  45. // This is done to optimize the compiled bytecode for size and performance.
  46. int id;
  47. missingId: {
  48. id = R.id.tvCancel;
  49. TextView tvCancel = rootView.findViewById(id);
  50. if (tvCancel == null) {
  51. break missingId;
  52. }
  53. id = R.id.tvContent1;
  54. TextView tvContent1 = rootView.findViewById(id);
  55. if (tvContent1 == null) {
  56. break missingId;
  57. }
  58. id = R.id.tvContent2;
  59. TextView tvContent2 = rootView.findViewById(id);
  60. if (tvContent2 == null) {
  61. break missingId;
  62. }
  63. id = R.id.tvSure;
  64. TextView tvSure = rootView.findViewById(id);
  65. if (tvSure == null) {
  66. break missingId;
  67. }
  68. id = R.id.tvTitle;
  69. TextView tvTitle = rootView.findViewById(id);
  70. if (tvTitle == null) {
  71. break missingId;
  72. }
  73. return new DialogPrivacyagreementBinding((LinearLayout) rootView, tvCancel, tvContent1,
  74. tvContent2, tvSure, tvTitle);
  75. }
  76. String missingId = rootView.getResources().getResourceName(id);
  77. throw new NullPointerException("Missing required view with ID: ".concat(missingId));
  78. }
  79. }

六.Adapter使用

1.Adapter代码

  1. public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
  2. private final List<String> mList;
  3. private final LayoutInflater mInflater;
  4. public MyAdapter(Activity activity, List<String> list) {
  5. mList = list;
  6. mInflater = LayoutInflater.from(activity);
  7. }
  8. @NonNull
  9. @Override
  10. public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
  11. ItemMyRecyclerviewBinding binding = ItemMyRecyclerviewBinding.inflate(mInflater, parent, false);
  12. return new ViewHolder(binding);
  13. }
  14. @Override
  15. public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
  16. holder.textView.setText(mList.get(position));
  17. holder.itemView.setOnClickListener(v -> LoggerUtils.logD("MyAdapter", "Item点击..."));
  18. }
  19. @Override
  20. public int getItemCount() {
  21. return mList.size();
  22. }
  23. /**
  24. * ViewHolder类
  25. */
  26. static class ViewHolder extends RecyclerView.ViewHolder {
  27. private ItemMyRecyclerviewBinding binding;
  28. private final TextView textView;
  29. public ViewHolder(ItemMyRecyclerviewBinding binding) {
  30. super(binding.getRoot());
  31. textView = binding.tvItem;
  32. }
  33. }
  34. }

2.Item布局

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="110dp">
  6. <TextView
  7. android:id="@+id/tv_item"
  8. android:layout_width="match_parent"
  9. android:layout_height="100dp"
  10. android:layout_marginBottom="10dp"
  11. android:background="@color/purple_200"
  12. android:gravity="center"
  13. android:textColor="@color/white"
  14. tools:ignore="MissingConstraints"
  15. tools:text="我是Item内容" />
  16. </androidx.constraintlayout.widget.ConstraintLayout>

3.源码

  1. public final class ItemMyRecyclerviewBinding implements ViewBinding {
  2. @NonNull
  3. private final ConstraintLayout rootView;
  4. @NonNull
  5. public final TextView tvItem;
  6. private ItemMyRecyclerviewBinding(@NonNull ConstraintLayout rootView, @NonNull TextView tvItem) {
  7. this.rootView = rootView;
  8. this.tvItem = tvItem;
  9. }
  10. @Override
  11. @NonNull
  12. public ConstraintLayout getRoot() {
  13. return rootView;
  14. }
  15. @NonNull
  16. public static ItemMyRecyclerviewBinding inflate(@NonNull LayoutInflater inflater) {
  17. return inflate(inflater, null, false);
  18. }
  19. @NonNull
  20. public static ItemMyRecyclerviewBinding inflate(@NonNull LayoutInflater inflater,
  21. @Nullable ViewGroup parent, boolean attachToParent) {
  22. View root = inflater.inflate(R.layout.item_my_recyclerview, parent, false);
  23. if (attachToParent) {
  24. parent.addView(root);
  25. }
  26. return bind(root);
  27. }
  28. @NonNull
  29. public static ItemMyRecyclerviewBinding bind(@NonNull View rootView) {
  30. // The body of this method is generated in a way you would not otherwise write.
  31. // This is done to optimize the compiled bytecode for size and performance.
  32. int id;
  33. missingId: {
  34. id = R.id.tv_item;
  35. TextView tvItem = rootView.findViewById(id);
  36. if (tvItem == null) {
  37. break missingId;
  38. }
  39. return new ItemMyRecyclerviewBinding((ConstraintLayout) rootView, tvItem);
  40. }
  41. String missingId = rootView.getResources().getResourceName(id);
  42. throw new NullPointerException("Missing required view with ID: ".concat(missingId));
  43. }
  44. }

七.include标签使用

1.include标签所在的布局

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent">
  6. <TextView
  7. android:id="@+id/tv_include_flags"
  8. android:layout_width="match_parent"
  9. android:layout_height="@dimen/dp_100"
  10. android:background="@color/purple_500"
  11. android:gravity="center"
  12. android:textColor="@color/white"
  13. tools:ignore="MissingConstraints" />
  14. </androidx.constraintlayout.widget.ConstraintLayout>

2.Activity布局

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. xmlns:app="http://schemas.android.com/apk/res-auto">
  7. <include
  8. android:id="@+id/include_layout"
  9. layout="@layout/include_flags"/>
  10. </androidx.constraintlayout.widget.ConstraintLayout>

3.Activity代码

  1. public class BaseModuleMainActivity extends AppCompatActivity {
  2. ActivityBaseModuleMainBinding binding;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. binding = ActivityBaseModuleMainBinding.inflate(getLayoutInflater());
  7. setContentView(binding.getRoot());
  8. binding.includeLayout.tvIncludeFlags.setText("我是Include标签引入的布局");
  9. }
  10. }

4.说明

include 标签必须设置id,使用时直接使用该id就可以找到include标签引入的布局了

八.include标签内有merge标签使用

1.include标签所在的布局

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <merge xmlns:android="http://schemas.android.com/apk/res/android">
  3. <Button
  4. android:id="@+id/include_merge_button1"
  5. android:layout_width="match_parent"
  6. android:layout_height="100dp"
  7. android:layout_marginTop="10dp"
  8. android:background="@color/purple_200"
  9. android:textColor="#FFFFFF" />
  10. <Button
  11. android:id="@+id/include_merge_button2"
  12. android:layout_width="match_parent"
  13. android:layout_height="100dp"
  14. android:layout_marginTop="10dp"
  15. android:background="@color/purple_500"
  16. android:textColor="#FFFFFF" />
  17. </merge>

2.Activity布局

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical">
  6. <include layout="@layout/include_flags" />
  7. </LinearLayout>

3.Activity代码

  1. public class BaseModuleMainActivity extends AppCompatActivity {
  2. ActivityBaseModuleMainBinding binding;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. binding = ActivityBaseModuleMainBinding.inflate(getLayoutInflater());
  7. setContentView(binding.getRoot());
  8. IncludeFlagsBinding mergeBinding = IncludeFlagsBinding.bind(binding.getRoot());
  9. mergeBinding.includeMergeButton1.setText("TextView001");
  10. mergeBinding.includeMergeButton2.setText("TextView002");
  11. }
  12. }

4.说明

<1> include 标签带 merge 标签,需要通过bind()将merge布局绑定到主布局上。

九.某些文件不想使用ViewBinding

如果为Module启用了视图绑定,则会为Module包含的每个XML布局文件生成一个绑定类绑定类的名称是通过将XML文件的名称转换为 Pascal 大小写并在末尾添加Binding一词来生成的

如果那个布局文件不需要生成绑定类(不想用这个功能)。可以将该布局的根视图中加入以下代码

tools:viewBindingIgnore="true"

添加改属性前

添加改属性后

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. xmlns:tools="http://schemas.android.com/tools"
  6. tools:viewBindingIgnore="true"
  7. android:orientation="vertical">
  8. <include layout="@layout/include_flags" />
  9. </LinearLayout>

十.原理

ViewBinding的原理就是 通过gradle插件在编译的中增加了新功能,当某个module开启ViewBinding功能后,编译的时候就去扫描此模块下的layout文件,生成对应的binding类。

文件路径

源码

  1. public final class ActivityBaseModuleMainBinding implements ViewBinding {
  2. @NonNull
  3. private final ConstraintLayout rootView;
  4. @NonNull
  5. public final TextView tvBaseModule;
  6. private ActivityBaseModuleMainBinding(@NonNull ConstraintLayout rootView,
  7. @NonNull TextView tvBaseModule) {
  8. this.rootView = rootView;
  9. this.tvBaseModule = tvBaseModule;
  10. }
  11. @Override
  12. @NonNull
  13. public ConstraintLayout getRoot() {
  14. return rootView;
  15. }
  16. @NonNull
  17. public static ActivityBaseModuleMainBinding inflate(@NonNull LayoutInflater inflater) {
  18. return inflate(inflater, null, false);
  19. }
  20. @NonNull
  21. public static ActivityBaseModuleMainBinding inflate(@NonNull LayoutInflater inflater,
  22. @Nullable ViewGroup parent, boolean attachToParent) {
  23. View root = inflater.inflate(R.layout.activity_base_module_main, parent, false);
  24. if (attachToParent) {
  25. parent.addView(root);
  26. }
  27. return bind(root);
  28. }
  29. @NonNull
  30. public static ActivityBaseModuleMainBinding bind(@NonNull View rootView) {
  31. // The body of this method is generated in a way you would not otherwise write.
  32. // This is done to optimize the compiled bytecode for size and performance.
  33. int id;
  34. missingId: {
  35. id = R.id.tv_base_module;
  36. TextView tvBaseModule = rootView.findViewById(id);
  37. if (tvBaseModule == null) {
  38. break missingId;
  39. }
  40. return new ActivityBaseModuleMainBinding((ConstraintLayout) rootView, tvBaseModule);
  41. }
  42. String missingId = rootView.getResources().getResourceName(id);
  43. throw new NullPointerException("Missing required view with ID: ".concat(missingId));
  44. }
  45. }

源码中可以看出,最终使用的仍然是findViewById,ViewBinding通过编译时扫描layout文件生成ViewBinding绑定类

与findViewById相比优点

<1> 空安全:由于视图绑定会创建对视图的直接引用,因此不存在因视图 ID 无效而引发 Null 指针异常的风险。此外,如果视图仅出现在布局的某些配置中(比如横竖屏布局内容差异),则绑定类中包含其引用的字段会使用 @Nullable 标记。

<2> 类型安全:每个绑定类中的字段均具有与它们在 XML 文件中引用的视图相匹配的类型。这意味着不存在发生类转换异常的风险。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/319885?site
推荐阅读
相关标签
  

闽ICP备14008679号