返回介绍

5.1 inflate 方法解析

发布于 2024-12-23 22:04:07 字数 4319 浏览 0 评论 0 收藏 0

inflate 方法主要是把布局资源实例化成 View 并返回。

通过 获取 LayoutInflater 的三种方式 我们知道,通过布局文件填充成 View 对象最终调用的是下面两个方法:

public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
  if (DEBUG) System.out.println("INFLATING from resource: " + resource);
	//获取布局资源的 xml 解析器,注意:在开头的时候我们强调过,普通的 xml 是不被支持的,必须是经过编译器处理过的。
  XmlResourceParser parser = getContext().getResources().getLayout(resource);
  try {
    return inflate(parser, root, attachToRoot);
  } finally {
    parser.close();
  }
} 

最终调用的是此方法:

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
  synchronized (mConstructorArgs) {
    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
		// from 传入的 Context
		final Context inflaterContext = mContext;
		// 判断 parser 是否是 AttributeSet,如果不是则用 XmlPullAttributes 去包装一下。
    final AttributeSet attrs = Xml.asAttributeSet(parser);
		// 保存之前的 Context
    Context lastContext = (Context) mConstructorArgs[0];
		// 赋值为传入的 Context
    mConstructorArgs[0] = inflaterContext;
		// 默认返回的是传入的 Parent
    View result = root;

    try {
      // 查找开始标签
      int type;
      while ((type = parser.next()) != XmlPullParser.START_TAG &&
          type != XmlPullParser.END_DOCUMENT) {
        // Empty
      }

			//如果没找到有效的开始标签则抛出 InflateException
      if (type != XmlPullParser.START_TAG) {
        throw new InflateException(parser.getPositionDescription()
            + ": No start tag found!");
      }
			
			//获取控件的名称
      final String name = parser.getName();
      
      if (DEBUG) {
        System.out.println("**************************");
        System.out.println("Creating root view: "
            + name);
        System.out.println("**************************");
      }

			// 如果根节点是“merge”标签
      if (TAG_MERGE.equals(name)) {
				// 根节点为空或者不添加到根节点上,则抛出异常。
				// 因为“merge”标签必须是要被添加到父节点上的,不能独立存在。
        if (root == null || !attachToRoot) {
          throw new InflateException("<merge /> can be used only with a valid "
              + "ViewGroup root and attachToRoot=true");
        }
				// 递归实例化 root(也就是传入 Parent)下所有的 View
        rInflate(parser, root, inflaterContext, attrs, false);
      } else {
				// temp 是当前 xml 的根节点的 View。通过父 View、View 名、Context、属性,来实例化 View。也即实例化根节点的 View。
        final View temp = createViewFromTag(root, name, inflaterContext, attrs);
				
        ViewGroup.LayoutParams params = null;
				
				// 如果传入 Parent 不为空
        if (root != null) {
          if (DEBUG) {
            System.out.println("Creating params from root: " +
                root);
          }
          // 创建父 View 类型的 LayoutParams 参数
          params = root.generateLayoutParams(attrs);
          if (!attachToRoot) {
						// 如果不把填充的 View 关联在父 View 上,则把父 View 的 LayoutParams 参数设置给它
            // 如果把填充的 View 关联在父 View 上,则会走下面 addView 的逻辑
						temp.setLayoutParams(params);
          }
        }

        if (DEBUG) {
          System.out.println("-----> start inflating children");
        }
        // 实例化根节点 View 下面的所有子 View。
				// TODO ..................
        rInflate(parser, temp, attrs, true);
        if (DEBUG) {
          System.out.println("-----> done inflating children");
        }

				// Google 建议关联所有找到的 View
        // 如果根节点不为 null,并且需要把根节点 View 关联到 Parent 上,则使用 addView 方法把布局填充成的 View 树添加到 Parent 上。
        if (root != null && attachToRoot) {
          root.addView(temp, params);
        }

				// 决定返回的 RootView(也即传入的 Parent)还是 xml 中的根节点的 View。
        // 如果传入的 Parent 为空 或 实例化的 View 不添加到 Parent 上,则返回布局文件的根节点的 View
				// 否则,返回 Parent
        if (root == null || !attachToRoot) {
          result = temp;
        }
      }

    } catch (XmlPullParserException e) {
      InflateException ex = new InflateException(e.getMessage());
      ex.initCause(e);
      throw ex;
    } catch (IOException e) {
      InflateException ex = new InflateException(
          parser.getPositionDescription()
          + ": " + e.getMessage());
      ex.initCause(e);
      throw ex;
    } finally {
      // Don't retain static reference on context.
			// 把这之前保存的 Context 从新放回全局变量中。
      mConstructorArgs[0] = lastContext;
      mConstructorArgs[1] = null;
    }

    Trace.traceEnd(Trace.TRACE_TAG_VIEW);

    return result;
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文