概念
LayoutContainer 是一個(gè)用于自動(dòng)解析布局并且自動(dòng)通過(guò)findViewById給對(duì)應(yīng)id的View 進(jìn)行初始化的接口。
應(yīng)用場(chǎng)景
我們先來(lái)看看'kotlin-android-extensions'這個(gè)插件,它會(huì)在 View,Activity 或者 Fragment 中生成一些額外的代碼,然后就可以使用 XML 中定義的 id 來(lái)引用 View了。
參考:Kotlin Android Extensions: Say goodbye to findViewById (KAD 04)
但是如果我們的場(chǎng)景不是 View,Activity 或者 Fragment 的時(shí)候呢?就無(wú)法使用這個(gè)插件了。但是 kotlin 提供了 LayoutContainer 插件,它的工作原理和 'kotlin-android-extensions' 差不多也是生成一些額外的代碼,目的就是為了生成findViewById 等代碼。
如何使用
實(shí)現(xiàn) LayoutContainer 并且給對(duì)應(yīng)的 containerView 賦值。然后在需要的地方直接使用這個(gè)布局定義的 id(例如下面的llRoomMode) 來(lái)應(yīng)用 View 即可,不需要再 findViewById。
class PartySettingsComponent(override var containerView: View? ) : LayoutContainer{
//隨便寫(xiě)一個(gè)代碼,找一個(gè)地方調(diào)用即可。
private fun initView() {
//加載一個(gè) View 出來(lái),并且賦值給 containerView (重要)
containerView = View.inflate(mRootComponent.activityContext, R.layout.view_dialog_party_settings, null)
//修改派對(duì)模式
llRoomMode.setOnClickListener {
mSettingDialog?.dismiss()
mProvider.onShowSwitchPartyMode()
}
}
在 app/build.gradle 添加如下代碼,不然無(wú)法引用到引用的id
androidExtensions {
experimental = true
}
工作原理
反編譯kotlin代碼
要查看它是如何工作的就得反編譯這個(gè)類(lèi)了。
現(xiàn)在來(lái)關(guān)注一下它是如何幫我們實(shí)例化控件的,下面的代碼是反編譯后的代碼,可以看到它會(huì)去調(diào)用 _$_findCachedViewById 來(lái)獲取指定id對(duì)應(yīng)的view對(duì)象。
((LinearLayout)this._$_findCachedViewById(id.llRoomMode)).setOnClickListener((OnClickListener)(new OnClickListener() {
public final void onClick(View it) {
BottomSheetDialog var10000 = PartySettingsComponent.this.mSettingDialog;
if (var10000 != null) {
var10000.dismiss();
}
PartySettingsComponent.this.mProvider.onShowSwitchPartyMode();
}
}));
_$_findCachedViewById 方法
從這個(gè)方法可以看出它優(yōu)先去集合中獲取,找不到就真正去 findViewById 然后再將其緩存起來(lái),實(shí)現(xiàn)還是比較簡(jiǎn)單的。
public View _$_findCachedViewById(int var1) {
if (this._$_findViewCache == null) {
this._$_findViewCache = new HashMap();
}
//這里做了個(gè)緩存
View var2 = (View)this._$_findViewCache.get(var1);
if (var2 == null) {
View var10000 = this.getContainerView();
if (var10000 == null) {
return null;
}
//找不到就去getContainerView()中findViewById查找,這個(gè)就是我們上面 inflate 出來(lái)的布局了。
var2 = var10000.findViewById(var1);
this._$_findViewCache.put(var1, var2);
}
return var2;
}
本文是筆者學(xué)習(xí)之后的總結(jié),方便日后查看學(xué)習(xí),有任何不對(duì)的地方請(qǐng)指正。
記錄于 2020年6月19號(hào)