天天看點

Kotlin Android Extensions遭廢棄,官方推薦使用ViewBindingKAE的問題ViewBinding的基本使用

Kotlin Android Extensions遭廢棄,官方推薦使用ViewBindingKAE的問題ViewBinding的基本使用

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
}