比
kotlin-android-extensions插件更好用的
ViewBinding
kotlin-android-extensions插件更好用的
ViewBinding
前言
由于今年作業比較忙,好久沒更新文章了,幾年做的專案比較多,最近會陸陸續續記錄一下今年遇到的問題或知識,
一、kotlin-android-extensions存在的問題
1、污染全域命名空間
2、不能暴露可空性資訊
3、僅支持 Kotlin 代碼
這里有篇文章有說明,具體可以參考這里:https://www.bennyhuo.com/2020/11/07/deprecated-kotlin-android-extensions/
注意:根據谷歌的未來計劃,在接下來的一年里,谷歌的團隊將共同棄用 synthetics,并繼續支持——“視圖系結 (View Binding)”
具體說明可以看這里:https://mp.weixin.qq.com/s/pa1YOFA1snTMYhrjnWqIgg
二、ViewBinding的使用
1、設定說明
將 viewBinding 元素添加到其 build.gradle 檔案中,如下例所示:
android {
...
viewBinding {
enabled = true
}
}
如果要忽略某個布局檔案,請將 tools:viewBindingIgnore="true" 屬性添加到相應布局檔案的根視圖中:
<LinearLayout
...
tools:viewBindingIgnore="true" >
...
</LinearLayout>
2、用法
啟用視圖系結功能后,系統會為該模塊中包含的每個 XML 布局檔案生成一個系結類,每個系結類均包含對根視圖以及具有 ID 的所有視圖的參考,系統會通過以下方式生成系結類的名稱:將 XML 檔案的名稱轉換為駝峰式大小寫,并在末尾添加“Binding”一詞,
例如,假設某個布局檔案的名稱為 result_profile.xml:
<LinearLayout ... >
<TextView android:id="@+id/name" />
<ImageView android:cropToPadding="true" />
<Button android:id="@+id/button"
android:background="@drawable/rounded_button" />
</LinearLayout>
所生成的系結類的名稱就為 ResultProfileBinding,此類具有兩個欄位:一個是名為 name 的 TextView,另一個是名為 button 的 Button,該布局中的 ImageView 沒有 ID,因此系結類中不存在對它的參考,
每個系結類還包含一個 getRoot() 方法,用于為相應布局檔案的根視圖提供直接參考,在此示例中,ResultProfileBinding 類中的 getRoot() 方法會回傳 LinearLayout 根視圖,
以下幾個部分介紹了生成的系結類在 Activity 和 Fragment 中的使用,
在 Activity 中使用視圖系結
如需設定系結類的實體以供 Activity 使用,請在 Activity 的 onCreate()方法中執行以下步驟:
- 呼叫生成的系結類中包含的靜態
inflate()方法,此操作會創建該系結類的實體以供 Activity 使用, - 通過呼叫
getRoot()方法或使用Kotlin屬性語法獲取對根視圖的參考, - 將根視圖傳遞到
setContentView(),使其成為螢屏上的活動視圖,
private lateinit var binding: ResultProfileBinding
override fun onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
binding = ResultProfileBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
您現在即可使用該系結類的實體來參考任何視圖:
binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }
在 Fragment 中使用視圖系結
如需設定系結類的實體以供 Fragment 使用,請在 Fragment 的 onCreateView() 方法中執行以下步驟:
- 呼叫生成的系結類中包含的靜態
inflate()方法,此操作會創建該系結類的實體以供 Fragment 使用, - 通過呼叫
getRoot()方法或使用Kotlin屬性語法獲取對根視圖的參考, - 從
onCreateView()方法回傳根視圖,使其成為螢屏上的活動視圖,
注意:inflate() 方法會要求您傳入LayoutInflater,如果布局已inflate,您可以呼叫系結類的靜態 bind() 方法,
private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = ResultProfileBinding.inflate(inflater, container, false)
val view = binding.root
return view
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
您現在即可使用該系結類的實體來參考任何視圖:
binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }
注意:Fragment 的存在時間比其視圖長,請務必在 Fragment 的 onDestroyView() 方法中清除對系結類實體的所有參考,
與 findViewById 的區別
- Null 安全
- 型別安全
與
DataBinding的對比
- 更快的編譯速度
- 易于使用
三、ViewBinding 的封裝
1、activity中的封裝
基類
abstract class BaseActivity<T : ViewBinding> : AppCompatActivity() {
private var mBinding: T? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(getViewBinding().also {
mBinding = it
}.root)
}
abstract fun getViewBinding(): T
override fun onDestroy() {
super.onDestroy()
mBinding = null
}
}
MainActivity繼承這個基類并實作getViewBinding這個方法`
override fun getViewBinding(): ActivityMainBinding {
return ActivityMainBinding.inflate(layoutInflater)
}
2、fragment中的封裝
基類
abstract class BaseFragment<T : ViewBinding> : Fragment() {
private var mBaseBinding: T? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return onCreateBinding(inflater, container, savedInstanceState).also {
mBaseBinding = it
}.root
}
abstract fun onCreateBinding(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): T
override fun onDestroyView() {
super.onDestroyView()
mBaseBinding = null
}
}
FirstFragment繼承基類并實作以下:
override fun onCreateBinding(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): FragmentEarnBinding {
return FragmentFirstBinding.inflate(inflater, container, false)
}
更好的封裝可以參考這篇文章:https://juejin.cn/post/6906153878312452103
四、使用時的問題
在使用include引入布局時
使用bind將include所包含的布局引入進來;
layoutToolBarBinding = LayoutToolBarBinding.bind(ActivityMainBinding.inflate(layoutInflater().root());
在使用ViewStub引入布局時
// mBinding是Activity或Fragment的viewbinding
// customViewstub為 Viewstub的id
mBinding.customViewstub.setOnInflateListener { stub, inflated ->
run {
//LayoutCustomBinding 為viewStuby所參考的布局生成的viewbinding
LayoutCustomBinding.bind(inflated)
}
}
mBinding.customViewstub.inflate()
您的關注和點贊是我分享的動力,如有幫助請勿吝嗇!ヽ( ̄▽ ̄)ノ
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/236691.html
標籤:其他
上一篇:親測有效,關于Android出現the emulator process for Android was killed.
下一篇:微信小程式無法上傳圖片到服務器
