携手创作,共同生长!这是我参与「日新方案 8 月更文应战」的第20天,点击检查活动详情

本篇文章主要是分析如何拦截ActivityView的创立流程,完结无感知的运用自定义View替换指定的体系View,这对于换肤、埋点设计等等将是非常有帮助的一种方式。

LayoutInflater.Factory2是个啥?

Activity内界面的创立是由LayoutInflater负责,LayoutInflater最终会交给内部的一个类型为LayoutInflater.Factory2factory2成员变量进行创立。

这个属性值能够外部自定义传入,默认的完结类为AppCompatDelegateImpl

超有用的Android开发技巧:拦截界面View创建

然后在AppCompatActivity初始化构造办法中向LayoutInflater注入AppCompatDelegateImpl:

超有用的Android开发技巧:拦截界面View创建

超有用的Android开发技巧:拦截界面View创建

超有用的Android开发技巧:拦截界面View创建

常见的ImageViewTextView被替换成AppcompatImageViewAppCompatTextView等便是凭借AppCompatDelegateImpl进行完结的。

这儿有个完结的小细节,在initDelegate()办法中,调用了addOnContextAvailableListener()办法传入一个监听事情完结的factory2注入,这个addOnContextAvailableListener()办法有什么魅力呢?

addOnContextAvailableListener()是干啥用的?

咱们先看下这个办法是干啥用的:

超有用的Android开发技巧:拦截界面View创建

超有用的Android开发技巧:拦截界面View创建

最终是将这个监听目标参加到了ContextAwareHelper类的内部mListeners调集中,咱们接下里看下这个监听目标调集最终是在哪里被调用的。

超有用的Android开发技巧:拦截界面View创建

超有用的Android开发技巧:拦截界面View创建

能够看到,这个调集最终在ComponetActivityonCreate()办法中调用,请注意,这个调用机遇仍是在父类的super.onCreate()办法前进行调用的。

所以咱们能够得出结论,addOnContextAvailableListener()增加的监听器将在父类onCreate()办法前进行调用。

这个用处的场景仍是比较多的,比方咱们设置Activity的主题就必须在父类的onCreate()办法前调用,凭借这个监听,能够轻松完结。

代码实战

请注意,这个factory2的设置必须在ActivityonCreate()办法前调用,所以咱们能够直接凭借addOnContextAvailableListener()进行完结,也能够重写onCreate()办法在指定方位完结。当然了,前者更加的灵活,这儿咱们仍是以后者进行举例。

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替换过去太麻烦 ,这个时候就能够运用咱们经常运用到的ApplicationregisterActivityLifecycleCallbacks()监听一切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创立的思想,咱们设置还能够凭借此完结界面黑白化的作用,非常的好用,每个开发者都应该去了解把握的知识点。