经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » Android » 查看文章
Android中LayoutInflater.inflater()的正确打开方式
来源:jb51  时间:2018/12/10 9:19:35  对本文有异议

前言

LayoutInflater在开发中使用频率很高,但是一直没有太知道LayoutInflater.from(context).inflate()的真正用法,今天就看看源码的流程。

首先来看from()的源码:

  1. /**
  2. * Obtains the LayoutInflater from the given context.
  3. */
  4. public static LayoutInflater from(Context context) {
  5. LayoutInflater LayoutInflater =
  6. (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  7. if (LayoutInflater == null) {
  8. throw new AssertionError("LayoutInflater not found.");
  9. }
  10. return LayoutInflater;
  11. }

其实就是从Context中获取Context.LAYOUT_INFLATER_SERVICE所对应的系统服务。这里涉及到Context实现以及服务创建的源码,不继续深究。

重点是通常所使用的inflate()方法,比较常用的就是这两个:

  • inflate(@LayoutRes int resource, @Nullable ViewGroup root)
  • inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)

另外两个方法inflate(XmlPullParser parser, @Nullable ViewGroup root)inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)

而两个参数的方法,实际也是调用了三个参数的inflate()方法,只是在三个参数传入了root!=null

  1. public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
  2. return inflate(resource, root, root != null);
  3. }

那我们就可以直接看三个参数的inflate()方法了,其中res.getLayout(resource)这句代码,已经将我们传入的layout布局的根布局的xml属性都加载到了XmlResourceParser中

  1. public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
  2. final Resources res = getContext().getResources();
  3. //省略代码
  4. final XmlResourceParser parser = res.getLayout(resource);
  5. try {
  6. return inflate(parser, root, attachToRoot);
  7. } finally {
  8. parser.close();
  9. }
  10. }

这里其实就会发现,最后return调用的其实是inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)这个方法,所谓的四个inflate()方法,其他三个只是对这个方法的重载,主要代码还是在这个方法中实现的

这部分代码较长,以注释的形式解释代码

  1. public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
  2. synchronized (mConstructorArgs) {
  3. Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
  4.  
  5. final Context inflaterContext = mContext;
  6. //1.通过XmlResourceParser对象转换成AttributeSet
  7. final AttributeSet attrs = Xml.asAttributeSet(parser);
  8. Context lastContext = (Context) mConstructorArgs[0];
  9. mConstructorArgs[0] = inflaterContext;
  10. View result = root;
  11.  
  12. try {
  13. //2.在xml中寻找根节点,如果类型是XmlPullParser.START_TAG或者XmlPullParser.END_DOCUMENT就会退出循环
  14. int type;
  15. while ((type = parser.next()) != XmlPullParser.START_TAG &&
  16. type != XmlPullParser.END_DOCUMENT) {
  17. // Empty
  18. }
  19. //3.如果根节点类型不是XmlPullParser.START_TAG将抛出异常
  20. if (type != XmlPullParser.START_TAG) {
  21. throw new InflateException(parser.getPositionDescription()
  22. + ": No start tag found!");
  23. }
  24.  
  25. final String name = parser.getName();
  26.  
  27. //4.判断根节点是否是merge标签
  28. if (TAG_MERGE.equals(name)) {
  29. if (root == null || !attachToRoot) {
  30. throw new InflateException("<merge /> can be used only with a valid "
  31. + "ViewGroup root and attachToRoot=true");
  32. }
  33.  
  34. rInflate(parser, root, inflaterContext, attrs, false);
  35. } else {
  36. //5.通过根节点创建临时的view对象
  37. final View temp = createViewFromTag(root, name, inflaterContext, attrs);
  38.  
  39. ViewGroup.LayoutParams params = null;
  40.  
  41. if (root != null) {
  42. //6.如果root不为空,则调用generateLayoutParams(attrs)获取root所对应LayoutParams对象
  43. params = root.generateLayoutParams(attrs);
  44. //是否attachToRoot
  45. if (!attachToRoot) {
  46. //7.如果attachToRoot为false,则使用root默认的LayoutParams作为临时view对象的属性
  47. temp.setLayoutParams(params);
  48. }
  49. }
  50.  
  51. //8.inflate xml的所有子节点
  52. rInflateChildren(parser, temp, attrs, true);
  53.  
  54. //9.判断是否需要将创建的临时view attach到root中
  55. if (root != null && attachToRoot) {
  56. root.addView(temp, params);
  57. }
  58.  
  59. //10.决定方法的返回值是root还是临时view
  60. if (root == null || !attachToRoot) {
  61. result = temp;
  62. }
  63. }
  64.  
  65. } catch (XmlPullParserException e) {
  66. final InflateException ie = new InflateException(e.getMessage(), e);
  67. ie.setStackTrace(EMPTY_STACK_TRACE);
  68. throw ie;
  69. } catch (Exception e) {
  70. final InflateException ie = new InflateException(parser.getPositionDescription()
  71. + ": " + e.getMessage(), e);
  72. ie.setStackTrace(EMPTY_STACK_TRACE);
  73. throw ie;
  74. } finally {
  75. mConstructorArgs[0] = lastContext;
  76. mConstructorArgs[1] = null;
  77.  
  78. Trace.traceEnd(Trace.TRACE_TAG_VIEW);
  79. }
  80.  
  81. return result;
  82. }
  83. }

1中的XmlResourceParser在之前所获取的,包含了layout中跟布局的属性数据。

6,7则是很多时候使用inflate方法之后,发现xml布局设置的宽高属性不生效的部分原因,有时候在RecyclerView中添加就会这样。如果root!=null且attachToRoot为false时,创建的view则会具有自身根节点属性值,与root对应的LayoutParam

9的判断决定了创建的view是否添加到root中,而10则决定了方法返回的是root还是view

总结

根据inflate的参数不同可以获得不同的返回值

root attachToRoot 返回值
null false(或者true) 返回resource对应的view对象,但是xml中根节点的属性没有生效
!=null false 返回resource对应的view对象,并且xml中根节点的属性生效,view对象的LayoutParam与root的LayoutParam对应
!=null true 返回root对象,对应resource创建的view对象,xml中根节点的属性生效,并且将会添加到root中

注意:attachToRoot默认为root!=null的值

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对w3xue的支持。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号