通過(guò)視圖綁定功能臭觉,您可以更輕松地編寫(xiě)可與視圖交互的代碼。在模塊中啟用視圖綁定之后,系統(tǒng)會(huì)為該模塊中的每個(gè) XML 布局文件生成一個(gè)綁定類(lèi)内地。綁定類(lèi)的實(shí)例包含對(duì)在相應(yīng)布局中具有 ID 的所有視圖的直接引用色罚。
Tip:Viewbinding在 Android Studio 3.6 Canary 11 及更高版本中可用碰缔,現(xiàn)在應(yīng)該沒(méi)有誰(shuí)的AS版本低于3.6了吧!
用上ViewBinding步驟總共分幾步戳护?——3步金抡!
1.啟用視圖綁定:
android {
viewBinding {
enabled = true
}
}
2.在activity_main.xml中創(chuàng)建控件
<Button
android:id="@+id/btnPost"
android:layout_width="match_parent"
android:layout_height="45dp"
android:text="提交"
android:gravity="center" />
3.Activity 中使用視圖綁定
var binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.btnPost.setOnClickListener {
Toast.makeText(applicationContext, "點(diǎn)擊了按鈕", Toast.LENGTH_SHORT).show()
}
源碼分析
在gradle文件中開(kāi)啟ViewBinding功能后,編譯器就會(huì)為此模塊下的每個(gè)布局文件都產(chǎn)生一個(gè)對(duì)應(yīng)的綁定類(lèi)。該demo下自動(dòng)了綁定類(lèi)ActivityMainBinding腌且,位置在:
主要代碼如下:
public final class ActivityMainBinding implements ViewBinding {
@NonNull
private final ConstraintLayout rootView;
@NonNull
public final Button btnPost;
private ActivityMainBinding(@NonNull ConstraintLayout rootView, @NonNull Button btnPost,
@NonNull EditText etAge, @NonNull EditText etHeight, @NonNull TextView tvAge,
@NonNull TextView tvHight) {
this.rootView = rootView;
this.btnPost = btnPost;
}
@Override
@NonNull
public ConstraintLayout getRoot() {
return rootView;
}
@NonNull
public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater) {
return inflate(inflater, null, false);
}
@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.btnPost;
Button btnPost = rootView.findViewById(id);
if (btnPost == null) {
break missingId;
}
return new ActivityMainBinding((ConstraintLayout) rootView, btnPost, etAge, etHeight, tvAge,
tvHight);
}
String missingId = rootView.getResources().getResourceName(id);
throw new NullPointerException("Missing required view with ID: ".concat(missingId));
}
會(huì)去實(shí)現(xiàn)ViewBinding接口竟终,實(shí)現(xiàn)getRoot()方法,返回的是布局最外層父View切蟋,通過(guò)Activity的 setContentView()方法可以為Activity設(shè)置內(nèi)容统捶。只要有id的控件會(huì)為其生成一個(gè)變量,其內(nèi)部找尋控件實(shí)質(zhì)還是用的findViewbyId,已經(jīng)幫我們自動(dòng)做了喘鸟。
與 findViewById 的區(qū)別
與使用 findViewById 相比匆绣,視圖綁定具有一些很顯著的優(yōu)點(diǎn):
Null 安全:由于視圖綁定會(huì)創(chuàng)建對(duì)視圖的直接引用,因此不存在因視圖 ID 無(wú)效而引發(fā) Null 指針異常的風(fēng)險(xiǎn)什黑。此外崎淳,如果視圖僅出現(xiàn)在布局的某些配置中,則綁定類(lèi)中包含其引用的字段會(huì)使用 @Nullable 標(biāo)記愕把。
類(lèi)型安全:每個(gè)綁定類(lèi)中的字段均具有與它們?cè)?XML 文件中引用的視圖相匹配的類(lèi)型拣凹。這意味著不存在發(fā)生類(lèi)轉(zhuǎn)換異常的風(fēng)險(xiǎn)。
為某個(gè)模塊啟用視圖綁定功能后恨豁,系統(tǒng)會(huì)為該模塊中包含的每個(gè) XML 布局文件生成一個(gè)綁定類(lèi)嚣镜。每個(gè)綁定類(lèi)均包含對(duì)根視圖以及具有 ID 的所有視圖的引用。系統(tǒng)會(huì)通過(guò)以下方式生成綁定類(lèi)的名稱(chēng):將 XML 文件的名稱(chēng)轉(zhuǎn)換為駝峰式大小寫(xiě)橘蜜,并在末尾添加“Binding”一詞菊匿。
與Butterknife區(qū)別
butterknife的主要原理:
- 首先會(huì)掃描java代碼中所有通過(guò)ButterKnife設(shè)置的注解比如@Bind,@OnClick等计福。
- 當(dāng)發(fā)現(xiàn)一個(gè)類(lèi)中含有任何一個(gè)注解時(shí)跌捆,遍歷每個(gè)注解對(duì)應(yīng)通過(guò)JavaPoet生成一個(gè)java類(lèi),這個(gè)類(lèi)實(shí)現(xiàn)了ViewBinder接口象颖。
- 這個(gè)ViewBinder類(lèi)中包含了所有對(duì)應(yīng)的代碼佩厚,比如@Bind注解對(duì)應(yīng)的findViewByid(),@OnClick對(duì)應(yīng)的setOnClickListener等等说订。
ButterKnife 整個(gè)過(guò)程是在項(xiàng)目編譯階段完成的抄瓦,編譯耗時(shí)但是運(yùn)行不耗時(shí)。ViewBinding比ButterKnife編譯更安全克蚂,編譯速度更快闺鲸,所以可以說(shuō)是Butterknife的終結(jié)者了。
與DataBinding的區(qū)別
視圖綁定和數(shù)據(jù)綁定均會(huì)生成可用于直接引用視圖的綁定類(lèi)埃叭。但是摸恍,視圖綁定旨在處理更簡(jiǎn)單的用例,與數(shù)據(jù)綁定相比赤屋,具有以下優(yōu)勢(shì):
- 更快的編譯速度:視圖綁定不需要處理注釋?zhuān)虼司幾g時(shí)間更短立镶。
- 易于使用:視圖綁定不需要特別標(biāo)記的 XML 布局文件,因此在應(yīng)用中采用速度更快类早。在模塊中啟用視圖綁定后媚媒,它會(huì)自動(dòng)應(yīng)用于該模塊的所有布局。
反過(guò)來(lái)涩僻,與數(shù)據(jù)綁定相比缭召,視圖綁定也具有以下限制:
- 視圖綁定不支持布局變量或布局表達(dá)式栈顷,因此不能用于直接在 XML 布局文件中聲明動(dòng)態(tài)界面內(nèi)容。
- 視圖綁定不支持雙向數(shù)據(jù)綁定嵌巷。
考慮到這些因素萄凤,在某些情況下,最好在項(xiàng)目中同時(shí)使用視圖綁定和數(shù)據(jù)綁定搪哪。您可以在需要高級(jí)功能的布局中使用數(shù)據(jù)綁定靡努,而在不需要高級(jí)功能的布局中使用視圖綁定。
kotlin-android-extensions插件
kotlin-android-extensions插件會(huì)在Activity晓折,frragment等組件中自動(dòng)生成各個(gè)方法去做findViewById惑朦,并將各View添加到HashMap緩存中供使用。
所以漓概,工具這么多漾月,在你的項(xiàng)目中使用哪個(gè),It's up to you.
參考:
https://developer.android.google.cn/topic/libraries/view-binding