从源码的角度说说Activity的setContentView的原理(二)

简介: 前文http://blog.csdn.net/sahadev_/article/details/49072045虽然讲解了LayoutInflate的整个过程,但是其中很多地方是不准确不充分的,这一节就详细讲一下我们上一节遗留的细节问题,我们遗留的问题有这些: 1.

前文http://blog.csdn.net/sahadev_/article/details/49072045虽然讲解了LayoutInflate的整个过程,但是其中很多地方是不准确不充分的,这一节就详细讲一下我们上一节遗留的细节问题,我们遗留的问题有这些:

1.在PhoneWindow的setContentView里我们看到了一个mLayoutInflater对象,我们还没清楚它从哪来?

2.mLayoutInflater对象后来所调用的那些方法有没有被重载?

3.mFactory,mFactory2, mPrivateFactory这三个对象是否不为空?如果系统默认给它设置了值,那么后来生成的View是不是就是通过它们来设置的呢?

好,接下来就让我们一起把这些问题解开:


1. 我们先来看看mLayoutInflater从哪来,我们推测它极有可能和我们一样是使用这样的方式得来的:

LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

但,这仅仅是推测,我们要看到实际的代码:

    public PhoneWindow(Context context) {
        super(context);
        mLayoutInflater = LayoutInflater.from(context);
    }

通过查看源码我们可以得知,在 PhoneWindow的构造方法里是LayoutInflater.from(context);的方式对mLayoutInflater对象进行了初始化,看来,它也是和我们一样使用了同一个系统提供的LayoutInflater对象,那么,系统提供的这个LayoutInflater对象是在哪被构造和添加进去的呢?这我们就需要去Context.getSystemService方法里一探究竟了:

我们知道getSystemService其实调用的就是ContextImpl的方法,ContextImpl是Context的具体实现类,我们进入ContextImpl的getSystemService中一探究竟:

    public Object getSystemService(String name) {
        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
        return fetcher == null ? null : fetcher.getService(this);
    }

好,看来所有的服务都是通过SYSTEM_SERVICE_MAP取出来的,那么我们看看这些服务什么时候被添加进去的,在 ContextImpl这个类中我们看到有个静态方法

    private static void registerService(String serviceName, ServiceFetcher fetcher) {
        if (!(fetcher instanceof StaticServiceFetcher)) {
            fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
        }
        SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
    }

看来所有的服务都是通过它加进去的,那什么时候加进去的呢,我们在这个类当中可以看到一段很长的静态代码块,在代码块中发现了它的身影:

    static {

	...

        registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
                }});

	...

        }

好吧,看来系统系统的 LayoutInflater的对象其实是由PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());这个方法构造出来的(又是PolicyManager,我们刚才看到它执行的makeNewWindow,看来它做了不少事情), 不用多说,我们直接进入Policy中看(不清楚这个过程的同学可以直接看这里 http://blog.csdn.net/sahadev_/article/details/49072045 ):

    public LayoutInflater makeNewLayoutInflater(Context context) {
        return new PhoneLayoutInflater(context);
    }
噢,原来所有的工作都是它在干啊!到这里,我们第一个问题就清楚了。


2.mLayoutInflater对象后来所调用的那些方法有没有被重载?其实这个问题我们直接进PhoneLayoutInflater中就可以知道答案:

    /** Override onCreateView to instantiate names that correspond to the
        widgets known to the Widget factory. If we don't find a match,
        call through to our super class.
    */
    @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
        for (String prefix : sClassPrefixList) {
            try {
                View view = createView(name, prefix, attrs);
                if (view != null) {
                    return view;
                }
            } catch (ClassNotFoundException e) {
                // In this case we want to let the base class take a crack
                // at it.
            }
        }

        return super.onCreateView(name, attrs);
    }

噢,原来我们在上一篇文章当中分析的onCreateView方法是没有被调用的,那看来父类中的这个方法的功能是不满足的,那我们分析分析被复写的这个方法:

我们可以看到这个方法内部在遍历一个字符串数组,这个字符串数组被定义在类里:

    private static final String[] sClassPrefixList = {
        "android.widget.",
        "android.webkit.",
        "android.app."
    };

在上一篇文章当中,我请大家在onCreateView中注意调用createView方法的第二个参数是"android.view.",这里被重写,看来是不满足了,子类实现了更为强大的功能,支持了更多的包进行加载,它这个过程一直在尝试去创建View,直到成功。好,我们第二个问题也解决完了。


3.mFactory,mFactory2, mPrivateFactory这三个对象是否不为空?看来这个问题我们就都知道了,PhoneLayoutInflater在构造的时候调用的是:

    public PhoneLayoutInflater(Context context) {
        super(context);
    }

后来也没有对它进行什么设置,所以看来它们都是空,这里这3个对象是开放给我们使用的,我们可以在View被加载的时候动态的修改它们的效果,这是个很强大的功能,比如动态修改皮肤什么的,希望你们可以手动去实现一下,,谢谢。


目录
相关文章
|
10月前
|
人工智能 分布式计算 容灾
MaxCompute年度发布
本次分享介绍了阿里云MaxCompute在过去一年中的企业级数仓新功能。MaxCompute自2009年诞生,现已服务阿里巴巴集团、蚂蚁集团及众多第三方客户,日处理千万级任务。新功能包括湖仓一体开放性、Data+AI结合、非结构化数据处理(如Object Table)、实时数据处理(如增量物化视图)、性能优化(如MCU2.0和智能调优)以及企业级安全合规能力(如同城容灾和数据脱敏)。这些改进提升了数据处理的效率、安全性和性价比。
|
机器学习/深度学习 人工智能 运维
智能运维:大数据与AI的融合之道###
【10月更文挑战第20天】 运维领域正经历一场静悄悄的变革,大数据与人工智能的深度融合正重塑着传统的运维模式。本文探讨了智能运维如何借助大数据分析和机器学习算法,实现从被动响应到主动预防的转变,提升系统稳定性和效率的同时,降低了运维成本。通过实例解析,揭示智能运维在现代IT架构中的核心价值,为读者提供一份关于未来运维趋势的深刻洞察。 ###
445 10
|
Web App开发 JavaScript 中间件
构建高效后端服务:Node.js与Express框架的完美结合
【10月更文挑战第21天】本文将引导你走进Node.js和Express框架的世界,探索它们如何共同打造一个高效、可扩展的后端服务。通过深入浅出的解释和实际代码示例,我们将一起理解这一组合的魅力所在,并学习如何利用它们来构建现代Web应用。
392 1
|
人工智能 搜索推荐 定位技术
证件照尺寸修改、图片背景换色、照片大小压缩…几个在线图片编辑、处理网站推荐
证件照尺寸修改、图片背景换色、照片大小压缩…几个在线图片编辑、处理网站推荐
362 1
|
机器学习/深度学习 存储 人工智能
AI在数学界的作用和影响
众所周知,数学在科学中占据至关重要的地位。爱因斯坦曾说,“纯数学能使我们发现概念和联系这些概念的规律,给了我们理解自然现象的钥匙。数学之所以比一切其它科学受到尊重,一个理由是因为它的命题是绝对可靠的,无可争辩的,而其它的科学经常处于被新发现的事实推翻的危险。”那么,AI在数学界有哪些作用?AI未来对数学界会有哪些颠覆性影响?现在我们来进行论述和探讨。
584 0
|
前端开发 JavaScript 测试技术
《小团队web技术搭建》(七)自动化部署方式(CI/CD)(二)
《小团队web技术搭建》(七)自动化部署方式(CI/CD)(二)
525 1
|
运维 安全 Linux
iBox-面向Flutter的一站式研发工作台
移动端开发领域面向发布和运维的 Web 版平台有很多,但是面向研发和调试以及把整个研发工作流串联起来的平台确很少,面对端上越来越多的技术栈以及越来越复杂的业务场景,团队的上手成本和协同成本也会大大提高,iBox 的初衷就是想解决这些问题,它也是 Flutter Desktop 技术在生产环境的一次尝试。
1612 1
官宣!我们和中国电信牵手了
近日,中国电信集团公司(以下简称“中国电信”)与阿里云正式签署合作协议,联合研发“天翼钉”。
1348 0
官宣!我们和中国电信牵手了
EMQ
|
监控 数据可视化 NoSQL
易操作、可观测的 MQTT Dashboard,集群数据尽在掌握
全新EMQX Dashbord一览,可观测性和可操作性大幅提升,通过Web页面轻松管理和监控MQTT集群,助力高效开发。
EMQ
626 0
易操作、可观测的 MQTT Dashboard,集群数据尽在掌握
|
API Android开发
激活Shizuku
激活Shizuku
2781 0