ViewBinding(視圖綁定)
通過ViewBinding,可以更輕松地編寫可與視圖交互的代碼。在模塊中啟用ViewBinding后,系統(tǒng)會為該模塊中的每個XML布局文件生成一個綁定類袜硫。綁定類的實例包含對在相應(yīng)布局中具有ID的所有視圖的直接引用吹缔。多數(shù)情況下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>
模塊開啟視圖綁定功能后,系統(tǒng)會為該模塊中包含的每個XML布局文件生成一個綁定類饵较。每個綁定類均包含對根View以及布局中具有ID的所有視圖的引用。系統(tǒng)生成綁定類的命名方式是:通過將XML文件的名稱去下劃線后轉(zhuǎn)換成駝峰式大小寫并在末尾添加"Binding"的方式遭赂。例如 activity_main.xml 會生成一個ActivityMainBinding的視圖綁定類循诉。如下為activity_main.xml文件的內(nèi)容
<?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布局文件對應(yīng)的ActivityMainBinding類,包含了對根視圖的引用及具有ID 的View的引用撇他,通過綁定類 具體實例的getRoot()方法來獲取根視圖的引用茄猫,視圖中具有ID的view則會在綁定類中生成相應(yīng)ID名稱對應(yīng)的字段,如此視圖中的"name_view"和"button"這兩個view會在綁定類中生成nameView 和button兩個字段(字段生成規(guī)則為去下劃線后改駝峰式大小寫命名)困肩。具體生成的綁定類如下:
// 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中使用:
上述綁定類中 我們發(fā)現(xiàn)有多個靜態(tài)類方法:
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)
這三個靜態(tài)方法的返回值都式綁定類類型的實例募疮,通過這個實例我們便可以獲取到相應(yīng)的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的區(qū)別:
1.Null安全僻弹,由于ViewBinding會創(chuàng)建對視圖的直接引用阿浓,因此不存在因視圖ID無效而引發(fā)的Null指針異常的風(fēng)險。此外如果視圖僅出現(xiàn)在布局的某些配置中蹋绽,則綁定類中包含其引用的字段會使用@Nullable標(biāo)記芭毙。
2.類型安全每個綁定類中的字段均具有與它們XML文件中引用的View相匹配的類型筋蓖,這意味著不存在類轉(zhuǎn)換異常的風(fēng)險。
這些差異意味著布局和代碼之間的不兼容將會導(dǎo)致構(gòu)建在編譯時失敗退敦,而非在運行時出現(xiàn)異常粘咖。