超有用的Android開發技巧:攔截界面View創建
highlight: vs theme: devui-blue
攜手創作,共同成長!這是我參與「掘金日新計劃 · 8 月更文挑戰」的第20天,點擊查看活動詳情
本篇文章主要是分析如何攔截
Activity
中View
的創建流程,實現無感知的使用自定義View替換指定的系統View,這對於換膚、埋點設計等等將是非常有幫助的一種方式。
LayoutInflater.Factory2
是個啥?
Activity
內界面的創建是由LayoutInflater
負責,LayoutInflater
最終會交給內部的一個類型為LayoutInflater.Factory2
的factory2
成員變量進行創建。
這個屬性值可以外部自定義傳入,默認的實現類為AppCompatDelegateImpl
:
然後在AppCompatActivity
的初始化構造方法中向LayoutInflater
注入AppCompatDelegateImpl
:
常見的ImageView
、TextView
被替換成AppcompatImageView
、AppCompatTextView
等就是藉助AppCompatDelegateImpl
進行實現的。
這裏有個實現的小細節,在initDelegate()
方法中,調用了addOnContextAvailableListener()
方法傳入一個監聽事件實現的factory2注入,這個addOnContextAvailableListener()
方法有什麼魅力呢?
addOnContextAvailableListener()
是幹啥用的?
咱們先看下這個方法是幹啥用的:
最終是將這個監聽對象加入到了ContextAwareHelper
類的內部mListeners
集合中,咱們接下里看下這個監聽對象集合最終是在哪裏被調用的。
可以看到,這個集合最終在ComponetActivity
的onCreate()
方法中調用,請注意,這個調用時機還是在父類的super.onCreate()
方法前進行調用的。
所以我們可以得出結論,addOnContextAvailableListener()
添加的監聽器將在父類onCreate()
方法前進行調用。
這個用處的場景還是比較多的,比如我們設置Activity
的主題就必須在父類的onCreate()
方法前調用,藉助這個監聽,可以輕鬆實現。
代碼實戰
請注意,這個
factory2
的設置必須在Activity
的onCreate()
方法前調用,所以我們可以直接藉助addOnContextAvailableListener()
進行實現,也可以重寫onCreate()
方法在指定位置實現。當然了,前者更加的靈活,這裏我們還是以後者進行舉例。
```kotlin override fun onCreate(savedInstanceState: Bundle?) { LayoutInflaterCompat.setFactory2(layoutInflater, object : LayoutInflater.Factory2 { override fun onCreateView( parent: View?, name: String, context: Context, attrs: AttributeSet ): View? {
return if (name == "要替換的系統View名稱") {
CustumeView()
} else delegate.createView(parent, name, context, attrs)
}
})
} ```
請注意,這裏也有一個實現的小細節,如果當某個系統View不屬於我們要替換的View,請繼續委託給AppCompatDelegateImpl
進行處理,這樣就保證了實現系統組件特有功能的前提下,又能完成我們的View替換工作。
統一所有界面View的替換工作
如果要替換View的界面非常多,一個Activity一個Activity替換過去太麻煩 ,這個時候就可以使用我們經常使用到的Application
的registerActivityLifecycleCallbacks()
監聽所有Activity
的創建流程,其中我們用到的方法就是onActivityPreCreated()
:
``` registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks { override fun onActivityPreCreated(activity: Activity, savedInstanceState: Bundle?) { LayoutInflaterCompat.setFactory2(activity.layoutInflater, object : LayoutInflater.Factory2 { override fun onCreateView( parent: View?, name: String, context: Context, attrs: AttributeSet ): View? {
return if (name == "要替換的系統View名稱") {
CustumeView()
} else (activity as? AppCompatActivity)?.delegate?.createView(parent, name, context, attrs) ?: null
}
override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
TODO("Not yet implemented")
}
})
}
} ```
不過這個Application.ActivityLifecycleCallbacks
接口要重寫好多無用的方法,太麻煩了,之前寫過一篇關於接口優化相關的文章嗎,詳情可以參考:接口使用額外重寫的無關方法太多?優化它
總結
之前看過很多換膚、埋點統計上報等相關文章,多多少少都介紹了向AppCompatActivity
中注入factory2
攔截系統View創建的思想,我們設置還可以藉助此實現界面黑白化的效果,非常的好用,每個開發者都應該去了解掌握的知識點。
- kotlin密封sealed class/interface的迭代之旅
- 2022年12月12日—2022年12月25日Android精品文章一覽
- Sqlite簡易性能優化方案,給你的應用插上“翅膀”
- 築基篇:設置界面的開發利器Preference Library,瞭解一下~
- Android消息機制完整的執行流程,瞭解一下
- 你可能需要了解下的Android開發技巧(二)
- 超有用的Android開發技巧:攔截界面View創建
- Handler創建的幾個必備知識點,瞭解一下
- Android消息機制中Message常用的幾種監控方式
- 數見不鮮的RecyclerView使用技巧,你瞭解嗎(一)?
- 常用到的幾個Kotlin開發技巧,減少對業務層代碼的入侵
- 超好用的官方core-ktx庫,瞭解一下(終)~
- Take a look,從delay()方法看協程的掛起與恢復
- 超好用的官方core-ktx庫,瞭解一下~
- 官方core-ktx庫能對SparseArray系列、Pair開發帶來哪些便利?
- 官方core-ktx庫能對富文本Span開發帶來哪些便利2
- 你需要了解的官方core-ktx庫能對開發帶來哪些便利1
- LeakCanary如何監聽Fragment、Fragment View、ViewModel銷燬時機?
- 非反射動態設置TabLayout指示器的寬度
- 探究EventBus粘性事件實現機制