美文网首页
超有用的Android开发技巧:拦截界面View创建

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

作者: _Jun | 来源:发表于2022-09-26 15:39 被阅读0次

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

    LayoutInflater.Factory2是个啥?

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

    这个属性值可以外部自定义传入,默认的实现类为AppCompatDelegateImpl

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

    常见的ImageViewTextView被替换成AppcompatImageViewAppCompatTextView等就是借助AppCompatDelegateImpl进行实现的。

    这里有个实现的小细节,在initDelegate()方法中,调用了addOnContextAvailableListener()方法传入一个监听事件实现的factory2注入,这个addOnContextAvailableListener()方法有什么魅力呢?

    addOnContextAvailableListener()是干啥用的?

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

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

    可以看到,这个集合最终在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创建的思想,我们设置还可以借助此实现界面黑白化的效果,非常的好用,每个开发者都应该去了解掌握的知识点。

    作者:长安皈故里
    链接:https://juejin.cn/post/7137305357415612452

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/irqxartx.html