超有用的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粘性事件实现机制