Android Hook View的创建流程
创始人
2024-02-09 07:18:40

前言

前面我们对setContentView的源码进行了深入的分析Android最全的setContentView源码分析,那了解了View的创建流程,我们可以做些什么呢?答案就是我们可以通过拦截View的创建流程去解析View对应的属性(如textColor、src、background等),然后进行APP的换肤!

具体拦截实现

前面我们分析过View的创建流程会交给Factory2.onCreateView()方法去实现,那我们就通过实现 LayoutInflater.factory2接口进行View的创建拦截!

  • 实现LayoutInflater.factory2接口
class BaseSkinActivity : BaseActivity(), LayoutInflater.Factory2
  • onCreate(savedInstanceState: Bundle?)中设置LayoutInflater.factory2
    override fun onCreate(savedInstanceState: Bundle?) {val layoutInflater = LayoutInflater.from(this)layoutInflater.factory2 = this  //当前activity实现 LayoutInflater.factory2接口super.onCreate(savedInstanceState)}
  • 在factory2接口方法中进行View的创建拦截处理
 override fun onCreateView(parent: View?,name: String,context: Context,attrs: AttributeSet): View? {val view = createView(parent, name, context, attrs)if (view != null) {//在这里可以通过attrs解析View的属性和值,进行对应的换肤操作}return view}private fun createView(parent: View?,name: String,context: Context,attrs: AttributeSet): View {//这里的实现参考系统中的AppCompatDelegateImpl.createView方法,直接抄if (appCompatViewInflater == null) {appCompatViewInflater = AppCompatViewInflater()}var inheritContext = falseif (IS_PRE_LOLLIPOP) {if (mLayoutIncludeDetector == null) {mLayoutIncludeDetector = LayoutIncludeDetector()}inheritContext = if (mLayoutIncludeDetector!!.detect(attrs)) {true} else {if (attrs is XmlPullParser // If we have a XmlPullParser, we can detect where we are in the layout) (attrs as XmlPullParser).depth > 1 // Otherwise we have to use the old heuristicelse shouldInheritContext(parent as ViewParent?)}}return appCompatViewInflater!!.createView(parent, name, context, attrs, inheritContext,IS_PRE_LOLLIPOP,  /* Only read android:theme pre-L (L+ handles this anyway) */true,  /* Read read app:theme as a fallback at all times for legacy reasons */VectorEnabledTintResources.shouldBeUsed() /* Only tint wrap the context if enabled */)}private fun shouldInheritContext(parent: ViewParent?): Boolean {var parent: ViewParent? = parentval windowDecor: View = window.decorViewwhile (true) {if (parent == null) {return true} else if (parent === windowDecor || parent !is View|| ViewCompat.isAttachedToWindow((parent as View?)!!)) {return false}parent = parent.getParent()}}

其中AppCompatViewInflater我们无法调用使用系统对应的createView方法,最简单的方式是我们直接复制一份相同的AppCompatViewInflater类,去设置createViewpublic方法即可,createView方法的实现完全可以参考系统中的AppCompatDelegateImpl.createView方法~~

总结

这里只是简单的提供了APP插件换肤的思路,实际开发中插件换肤需要考虑的问题是比较多的,如多套皮肤的管理、自定义View的处理等等问题,但插件换肤的核心就是Hook View的创建流程,从而替换View的属性,说到底还是对源码的深刻理解。

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

相关内容

热门资讯

悦读丨一心一意,十全十美:在第... (来源:现代商业银行杂志)文|中国工商银行河北省分行团委书记 李嘉懿一心一意,是爱情最朴素的誓言;十...
委内瑞拉称拦截一架非法飞越其领... 本文转自【央视新闻客户端】;当地时间12月2日,委内瑞拉玻利瓦尔国民武装部队战略作战指挥官多明戈·埃...
金融活水润绿能 近日,甘肃省兰州市东城区清洁智慧热源项目的建设工地一派忙碌景象。该项目是兰州市重点新能源热源项目之一...
因势利导应对西北暖湿化 徐 骏作(新华社发) 戈壁荒滩下了创纪录的连阴雨,沙漠腹地出现汹涌洪水……近年来,我国西北地区出现一...
航贸金融加速数智化转型 近日,第八届虹桥国际经济论坛“航贸金融支持跨境贸易高质量发展”分论坛在国家会展中心(上海)举办。航贸...