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相匹配的类型,这意味着不存在类转换异常的风险。
这些差异意味着布局和代码之间的不兼容将会导致构建在编译时失败,而非在运行时出现异常。
网友评论