前文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 thewidgets 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被加载的时候动态的修改它们的效果,这是个很强大的功能,比如动态修改皮肤什么的,希望你们可以手动去实现一下,☺,谢谢。

从源码的角度说说Activity的setContentView的原理(二)相关推荐

  1. 从源码的角度说说Activity的setContentView的原理

    我们在Activity开发的时候天天会用到这个方法,有时候还需要根据需求在setContentView调用的时候做一些动作,因此我们就需要知道它内部是如何工作的,我们来一起看一下: setConten ...

  2. 【Android 启动过程】Activity 启动源码分析 ( ActivityThread -> Activity、主线程阶段 二 )

    文章目录 前言 一.ActivityThread 类 handleLaunchActivity -> performLaunchActivity 方法 二.Instrumentation.new ...

  3. 从 Android 6.0 源码的角度剖析 Binder 工作原理 | CSDN 博文精选

    在从Android 6.0源码的角度剖析Activity的启动过程一文(https://blog.csdn.net/AndrExpert/article/details/81488503)中,我们了解 ...

  4. 从Android 6.0源码的角度剖析View的绘制原理

    在从Android 6.0源码的角度剖析Activity的启动过程和从Android 6.0源码的角度剖析Window内部机制原理的文章中,我们分别详细地阐述了一个界面(Activity)从启动到显示 ...

  5. Android Fragment 从源码的角度去解析(上)

    ###1.概述 本来想着昨天星期五可以早点休息,今天可以早点起来跑步,可没想到事情那么的多,晚上有人问我主页怎么做到点击才去加载Fragment数据,而不是一进入主页就去加载所有的数据,在这里自己就对 ...

  6. Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

    <div id="container">         <div id="header">     <div class=&qu ...

  7. 【Android 启动过程】Activity 启动源码分析 ( ActivityThread -> Activity、主线程阶段 一 )

    文章目录 前言 一.ClientTransactionHandler.scheduleTransaction 二.ActivityThread.H 处理 EXECUTE_TRANSACTION 消息 ...

  8. 【转】Android事件分发机制完全解析,带你从源码的角度彻底理解(下)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9153761 记得在前面的文章中,我带大家一起从源码的角度分析了Android中Vi ...

  9. 【动态代理】从源码实现角度剖析JDK动态代理

    相比于静态代理,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定一组接口及目标类对象就能动态的获得代理对象.动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代 ...

最新文章

  1. 山东省2021年普通高考成绩录取去向查询,2018年山东高考录取去向查询时间及入口...
  2. 一行代码完成js对象数组的深拷贝
  3. ABAP 字符串操作
  4. Ubuntu16.04下CUDA 9.0 + cuDNN v7.0 + tensorflow 1.6.0(GPU)环境搭建
  5. wxWidgets:wxString概述
  6. 另一个分区工具:GNU 的 parted(转)
  7. Android 开发者们,如何使用 Python 来扩展 adb 命令?
  8. 问卷星的自动答题脚本
  9. 自己写的一个GPS卫星地图
  10. java无法远程读写HDFS系统解决方案
  11. Elasticearch 搜索引擎(1
  12. Idear创建Maven项目
  13. 教程篇(7.0) 08. FortiGate安全 Web过滤 ❀ Fortinet 网络安全专家 NSE 4
  14. 修改linux系统的root用户密码,linux系统下修改root用户密码
  15. JDBC与数据库连接
  16. 2022.12.23-Python100day-day05-面向对象编程
  17. 深入理解Linux虚拟内存管理(二)
  18. 微信小程序 特殊布局下,页面上拉触底事件onReachBottom无法触发解决方法
  19. ROS rosbridge
  20. 美颜sdk对直播平台有多重要?为什么需要接入直播美颜sdk?

热门文章

  1. Linux i2c子系统驱动probe
  2. java过去配置文件的值_java对.properties配置文件操作
  3. MongoDB基本应用操作整理
  4. ajax 五种状态,ajax的五种状态
  5. 智慧交通day02-车流量检测实现10:多目标追踪实现
  6. Vue权限控制——动态注册路由
  7. 天池 在线编程 最佳利用率(二分查找 + 哈希)
  8. LeetCode 276. 栅栏涂色(DP)
  9. LeetCode 1064. 不动点(二分查找)
  10. LeetCode 667. 优美的排列 II(找规律)