ButterKnife被棄用,ViewBinding才是findView的未來?

最近Android Studio更新到了4.1版本,發現項目中使用ButterKnife注解id的代碼出現了警告,警告信息如下:

Resource IDs will be non-final in Android Gradle Plugin version 5.0, avoid using them as annotation attributes

從警告信息中可以看到在Gradle 5.0的插件中Resource 的Id值將不會再是final類型,因此應該避免在注解屬性中使用Id。這意味著當我們把Gradle插件升級到5.0版本之后ButterKnife將無法再被使用!同時,我們在ButterKnife的官方文檔上也看到了ButterKnife被標注棄用的信息:

陪伴我們多年,曾經輝煌一時,不可一世的ButterKnife也要壽終正寢,即將迎來它生命的終點。借這個機會,我們不妨來回顧一下Android開發中findView的發展史,以及展望下findView的未來。

一、Android綁定View的發展史

從Android系統誕生至今,在代碼中findView一直是Android開發者無法繞開的一道程序。從最初的findViewbyId到如今炙手可熱的ViewBinding,期間涌現出了許多findView的方式,它們讓findView變得更加簡單,也讓我們的代碼變得更加簡潔。但隨著Android新技術的發展,這些findView的方法也正在被一個一個的拋棄。本節內容我們就來回顧一下Android開發中findView的發展史。

1.findViewById

findViewById是Android開發中最原始,也是最基礎的一種獲取View的方法。它由Google官方提供,在Android開發生態的早期也是唯一一種能夠獲取View的方式。雖然它使用簡單且根正苗紅,貫穿古今。但由于高度重復的代碼結構深受開發者詬病。在一個復雜布局的頁面僅僅是findViewById的代碼往往就能達到數十行。開發者無時無刻不想著棄用這一方案,因此后續衍生出了多種獲取View的方式來簡化代碼。但萬變不離其宗,歸根結底,這些方式最終都還是通過findViewById來實現的。雖然它是最不被開發者認可的一種的方式,但時至今日開發者也無法擺脫它籠罩著的陰影。一臉你看不慣我你打我呀的表情!

2.ButterKnife

就在大家都在唾棄findViewById的大量重復代碼時,一個插件橫空出世。它通過一個BindView注解,傳入一個Resource Id就能輕松獲取到Id對應的View。代碼如下:

它就是紅極一時,時至今日大家依然還在用著的ButterKnife。ButterKnife通過最前沿的Java技術(最初的版本可能是反射,未加考究)–Java編譯時注解處理器,在編譯時自動生成findViewById的代碼。例如,上邊的例子通過ButterKnife會生成一個MainActivity_ViewBinding 類,在這個類中通過findViewById為mTextView賦值,其代碼如下:

這一操作省去了開發者手動編寫findViewById的時間,大大簡化了代碼,同時提高了開發效率。在當時的開發者看來ButterKnife不得不說是一個神器,以至于到后來成了Android項目開發的標配。

后來,隨著Android Studio的誕生,Eclipse開發Android項目逐漸淡出歷史舞臺。Android studio的出現,帶來了全新的技術,模塊化風靡一時。大概在這個時候,Google官方似乎就已經有了改造R類的想法。在Android項目的library模塊中,生成R類中的成員變量就已經改為了非final修飾。同時,Google官方也不再建議在app模塊的代碼中使用像:switch(view.getId())這樣的代碼。

正如Android studio官網文檔《Non-constant Fields in Case Labels》上給出的原因:

In other words, the constants are not final in a library project. The reason for this is simple: When multiple library projects are combined, the actual values of the fields (which must be unique) could collide. Before ADT 14, all fields were final, so as a result, all libraries had to have all their resources and associated Java code recompiled along with the main project whenever they were used. This was bad for performance, since it made builds very slow. It also prevented distributing library projects that didn’t include the source code, limiting the usage scope of library projects.

這一改變直接致使ButterKnife無法在Android項目的library模塊中使用。而此時,ButterKnife正是如日中天,追隨的開發者不計其數。為了能夠讓ButterKnife運行在library模塊,ButterKnife的作者Jake Wharton大佬曲線救國,通過生成R2類讓ButterKnife在library模塊中復活,并且得以發展壯大。但不得不說,此時的ButterKnife就已經埋下了深深的隱患,并導致了其最終的潰敗。

3.DataBinding

DataBinding是Google官方在2015年谷歌I/O大會上發布的一個數據綁定框架,它并非專為findView而生,而是作為MVVM架構的雙向綁定數據的工具。findView的功能僅僅是DataBinding的一個附贈品。

4.Kotlin Android Extensions

2017年Google I/O開發者大會中,Google宣布Kotlin成為Android開發的一級語言,自此,Kotlin “轉正”與Java并駕齊驅。而JetBrain推出的Kotlin Android Extension(以下簡稱KAE)插件成為了有史以來最簡單的獲取View的方法,簡單到無需任何代碼,直接通過id作為View使用。這一功能足以讓所有Android開發者抓狂,紛紛感嘆這才是findView的未來啊,終于可以和裹挾開發者十多年的findViewById說拜拜了!

作為一個Android開發者,不知道你是否會好奇Kotlin是如何將Id作為View的?我們不妨寫一個簡單的例子:

布局文件中TextView的id設置為“textView”,則在Activity中可以直接將textView作為一個TextView來使用。我們通過Android Studio的工具將kotlin的字節碼反編譯成Java代碼看下

通過上述操作,打開kotlin的字節碼后,再通過Decompile反編譯成Java代碼,則會得到如下圖所示的結果:

通過反編譯得到的Java代碼我們發現Kotlin的這一操作其實也是通過findViewById實現的。只是通過插件的方式讓我們感覺上是用了View的Id。

通過Kotlin的擴展插件來find view,無疑是一種優秀的方案。但這一方案并不是無懈可擊。它存在以下幾個缺點:

?·?類型安全:res下的任何id都可以被訪問,有可能因訪問了非當前Layout下的id而出錯

?·?空安全:這主要體現在Configuration中的對應布局不全時,運行時可能出現NPE

?·?兼容性:只能在kotlin中使用,java不友好

?·?局限性:不能跨module使用

也正是這幾個缺點導致了KAE的大潰敗。隨著Google對親兒子ViewBinding的大力推廣,KAE最終也招架不住,只能繳械投降—Jetbrains在官網宣布廢棄KAE,并推薦開發者使用ViewBinding.

5.ViewBinding

到這里,以上提到的多種findView方案都已經被廢棄,唯獨只剩Google官方正在大力推廣的ViewBinding組件。ViewBinding是Google在2019年I/O大會上公布的一款Android視圖綁定工具。它的使用方式有點類似DataBinding,但相比DataBinding,ViewBinding是一個更輕量級、更純粹的findViewById的替代方案。它具有以下幾個優點:

? ? ·?類型安全: ViewBinding會基于布局中的View生成類型正確的屬性。比如,在布局中放入了一個 TextView ,視圖綁定就會暴露出一個 TextView 類型的屬性供開發中使用。

????·?空安全:ViewBinding會檢測某個視圖是不是只在一些配置下存在,并依據結果生成帶有 @Nullable 注解的屬性。所以即使在多種配置下定義的布局文件,視圖綁定依然能夠保證空安全。

????·?ViewBinding生成的綁定類是一個Java類,并且添加了Kotlin的注解,可以很好的支持 Java 和 Kotlin 兩種編程語言。

同時,Google官方還給出了一個ViewBinding、ButterKnife以及KAE的對比,如下圖:

總而言之,到目前為止除了ViewBinding我們已經別無選擇。那么不妨接下來詳細探究下ViewBinding的使用方法。

二、ViewBinding使用詳解

1.開啟ViewBinding

Android Studio對于ViewBinding的支持是從3.6版本開始的,AS 3.6版本內置了Gradle插件。只需要在build.gradle中通過以下配置即可開啟ViewBinding:

如果,你的項目存在多個模塊,則需要在每個模塊的gradle中添加上述配置。完成以上配置后ViewBinding會為所有布局文件自動生成對應的綁定類。且無須修改原有布局的 XML 文件,ViewBinding會根據現有的布局自動完成所有工作。

2.在Activity中使用ViewBinding

首先編寫activity_main.xml的布局文件,如下:

完成后gradle插件會自動生成一個名為ActivityMainBinding的Java類,在Activity中通過ActivityMainBinding獲取Binding實例,如下:

3.ViewBinding與include標簽

在項目開發中,通常我們會使用include標簽來簡化布局文件,那么在使用了include標簽的布局文件中,應該如何使用ViewBinding呢?且看代碼:

上述兩個布局文件會分別生成ActivityMainBinding與LayoutIncludeBinding兩個Java類,并且ActivityMainBinding類中通過組合依賴了LayoutIncludeBinding類。因此,使用方式如下:

如果layout_include.xml文件位于子模塊,經實踐與以上代碼的使用方式并無任何差異,但一定要在子模塊中開啟ViewBinding才行。

4.ViewBinding在Fragment中的使用

在Fragment中使用ViewBinding與Activity中有些差異,這里為了簡便,我們使用上述中的activity_main.xml作為Fragment的布局文件,則Fragment的代碼如下:

5.ViewBinding在RecyclerView#Adapter中的使用

布局文件不再貼出,直接看Adapter的代碼,如下所示:

通過以上幾個實例可以看到ViewBinding的使用是非常簡單的。而ViewBinding的實現原理也并不難,Gradle插件會根據布局文件在項目的build目錄下生成相應的ViewBinding類,并且,最終也是通過findViewById來完成View的獲取的。具體實現代碼不再貼出,感興趣的同學可以自行查看。

三、展望與總結

時代在發展,Android獲取View的方式仍在變化。ViewBinding無疑是一個優秀的組件,但它真的是Android開發中獲取View的最優方案嗎?顯然,并不是!因為ViewBinding歸根結底還是通過findViewById實現,且需要插件生成相關的Binding類,雖然省去了手動編寫,但是ViewBinding仍然沒能解決代碼冗余的問題。那什么才是findViewById的未來呢?大概最好的findView就是沒有findView吧!目前Google正在朝著這一方向努力,正在開發的Jetpack Compose庫就是要取代Android的布局文件,徹底消除findViewById。相信在未來某一天,隨著Jetpack Compose庫的普及,這個曠日持久的findViewById之爭也最終會畫上一個圓滿的句號。

參考&推薦閱讀

Non-constant Fields in Case Labels

The future of Kotlin Android Extensions

Kotlin Android Extensions遭廢棄,官方推薦使用ViewBinding

使用視圖綁定替代 findViewById

開源庫推薦

BannerViewPager

一個基于ViewPager2實現的具有強大功能的無限輪播庫。支持多種頁面切換效果和指示器樣式。

ViewPagerIndicator

一個適用于ViewPager和ViewPager2的指示器,支持多種滑塊樣式及滑動模式

————————————————

版權聲明:本文為CSDN博主「我賭一包辣條」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。

原文鏈接:https://blog.csdn.net/qq_20521573/article/details/110278319

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容