![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiIXZ05WZj91YpB3IwczX0xiRGZkRGZ0Xy9GbvNGL2EzXlpXazxCaahVYyY0RkBnWzwEMW1mY1RzRapnTtxkb5ckYplTeMZTTINGMShUYfRHelRHLwEzX39GZhh2css2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xyayFWbyVGdhd3LcV2Zh1Wa9M3clN2byBXLzN3btg3Pn5GcuMTNzUzNxADMyITMxAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
https://youtrack.jetbrains.com/issue/KT-42121
As the @Parcelize functionality is extracted (KT-42120), the rest of the Android Extensions functionality can be deprecated in favour of View Binding.
The existing Android Extensions plugin will continue to work, however, a warning message will be shown.
記得曾經在《誰才是ButterKnife的終結者?》一文中大膽猜測ViewBinding将替代KAE,果然被不幸言中,近期KAE被正式廢棄。
KAE的問題
KAE被廢棄是因為存在以下幾方面問題:
- 類型安全:res下的任何id都可以被通路,有可能因通路了非目前Layout下的id而出錯
- 空安全:這主要展現在Configuration中的對應布局不全時,運作時可能出現NPE
- 相容性:隻能在kotlin中使用,java不友好
- 局限性:不能跨module使用
KAE被廢的同時官方也給出了解決方案:遷移至ViewBinding。因為ViewBinding解決了KAE的主要缺陷:Null safety 與 Type safety,安全性更高。
ViewBinding的基本使用
開啟ViewBinding很簡單,隻需在
build.gradle
中增加一下配置
android {
...
buildFeatures {
viewBinding true
}
}
ViewBinding會在編譯期根據layout檔案生成對應的class
<LinearLayout ... >
<TextView android:id="@+id/name" />
<ImageView android:cropToPadding="true" />
<Button android:id="@+id/btn"
android:background="@drawable/rounded_button" />
</LinearLayout>
針對上面
activity_main.xml
,會生成
ActivityMainBinding
的class,
public final class ActivityMainBinding implements ViewBinding {
@NonNull
public final TextView name;
@NonNull
public final Button btn;
@NonNull
public View getRoot() {}
}
兩個成員
name
和
btn
,分别對應layout中的TextView和Button。
getRoot()
方法傳回layout的跟節點,上例中即LinearLayout
<LinearLayout
...
tools:viewBindingIgnore="true" >
...
</LinearLayout>
通過
tools:viewBindingIgnore="true"
可以禁止ViewBinding的生成,是以class中沒有ImageView對應的成員
在Activity中建立ViewBinding執行個體
private lateinit var binding: ActivityMainBinding
override fun onCreate (savedInstanceState: Bundle?) {
super.onCreate (savedInstanceState)
binding = ActivityMainBinding.inflate (layoutInflater)
val view = binding.root
setContentView (view)
}
并在适當的時候通路其成員
binding.name.text = viewModel.name
binding.btn.setOnClickListener {viewModel.userClicked ()}
Fragment中的使用
可以在Fragment的
onCreateView
中建立binding,然後在
onDestroyView
中銷毀
override fun onCreateView (
inflater: LayoutInflater,
container: ViewGroup ?,
savedInstanceState: Bundle?
): View? {
_binding = ActivityMainBinding.inflate (inflater, container, false)
val view = binding.root
return view
}
override fun onDestroyView () {
super.onDestroyView ()
_binding = null
}