转载

Android LayoutInflater和findViewById 源码详解

LayoutInflater大家很熟悉,简单点说就是布局文件XML解析器,setContentView函数也是调用了LayoutInflater

用法:

View view = LayoutInflater.from(this).inflate(R.layout.activity_main, null);

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

上面的用法本质上都是一样.

控制台打印 重复调用LayoutInflater.from(this)  同一个进程下面 实例是单例

com.android.internal.policy.impl.PhoneLayoutInflater@420dcf80

com.android.internal.policy.impl.PhoneLayoutInflater@420dcf80

com.android.internal.policy.impl.PhoneLayoutInflater@420dcf80

首先 LayoutInflater 是一个抽象类,实例化对象是从Service取出的。但是并没有到底层Binder去实例化对象。最终实例对象是PhoneLayoutInflater类      public static LayoutInflater from(Context context) {         LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);         if (LayoutInflater == null) {             throw new AssertionError("LayoutInflater not found.");         }         return LayoutInflater;     }
从Activity父类可以找到 getSystemService方法 public Object getSystemService(String name) {  if (LAYOUT_INFLATER_SERVICE.equals(name)) {   if (mInflater == null) {    mInflater = LayoutInflater.from(mBase).cloneInContext(this); //在这个地方实例化的,主要关联到mBase Context对象实例   }   return mInflater;  }  return mBase.getSystemService(name); } 
重点是Context的实例化对象 有个子类 ContextImpl.java 里面注册了相关Service     public Object getSystemService(String name) {         ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);         return fetcher == null ? null : fetcher.getService(this);     }
SYSTEM_SERVICE_MAP 是个hashMap  注册的服务都存在这个地方,对象被缓存。 private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String, ServiceFetcher>(); abstract static class StaticServiceFetcher extends ServiceFetcher {  private Object mCachedInstance;  @Override  public final Object getService(ContextImpl unused) {   synchronized (StaticServiceFetcher.this) {    Object service = mCachedInstance;    if (service != null) {     return service;    }    return mCachedInstance = createStaticService();   }  }  public abstract Object createStaticService(); //这个用于创建static服务 } registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() { //创建独立的对象 用于LayoutInflater  public Object createService(ContextImpl ctx) {     return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext()); }}); 
/*package*/ static class ServiceFetcher {  int mContextCacheIndex = -1;  /**   * Main entrypoint; only override if you don't need caching.   */  public Object getService(ContextImpl ctx) {// ContextImpl实例。   ArrayList<Object> cache = ctx.mServiceCache;   Object service;   synchronized (cache) {    if (cache.size() == 0) {     // Initialize the cache vector on first access.     // At this point sNextPerContextServiceCacheIndex     // is the number of potential services that are     // cached per-Context.     for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {      cache.add(null);     }    } else {     service = cache.get(mContextCacheIndex);//获取缓存是否存在     if (service != null) {      return service;     }    }    service = createService(ctx); //用来缓存服务实例    cache.set(mContextCacheIndex, service);    return service;   }  }  /**   * Override this to create a new per-Context instance of the   * service.  getService() will handle locking and caching.   */  public Object createService(ContextImpl ctx) {   throw new RuntimeException("Not implemented");  } } 
com.android.internal.policy.PolicyManager 找到了LayoutInflater的实现类 这个类算是个代理类 本质上是  private static final String POLICY_IMPL_CLASS_NAME =  "com.android.internal.policy.impl.Policy"; policy/src/com/android/internal/policy/impl 目录下 public LayoutInflater makeNewLayoutInflater(Context context) {  return new PhoneLayoutInflater(context); //实例化 } policy/src/com/android/internal/policy/impl/PhoneLayoutInflater 回到LayoutInflater 递归解析XML 使用的是XMl Pull Parser解析器 public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) { } 
rInflate开始递归 都是XML解析 void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs,   boolean finishInflate) throws XmlPullParserException, IOException {  final int depth = parser.getDepth();  int type;  while (((type = parser.next()) != XmlPullParser.END_TAG ||    parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {   if (type != XmlPullParser.START_TAG) {    continue;   }   final String name = parser.getName();   if (TAG_REQUEST_FOCUS.equals(name)) {    parseRequestFocus(parser, parent);   } else if (TAG_INCLUDE.equals(name)) {    if (parser.getDepth() == 0) {     throw new InflateException("<include /> cannot be the root element");    }    parseInclude(parser, parent, attrs);   } else if (TAG_MERGE.equals(name)) {    throw new InflateException("<merge /> must be the root element");   } else if (TAG_1995.equals(name)) {    final View view = new BlinkLayout(mContext, attrs);    final ViewGroup viewGroup = (ViewGroup) parent;    final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);    rInflate(parser, view, attrs, true);    viewGroup.addView(view, params);       } else {    final View view = createViewFromTag(parent, name, attrs);    final ViewGroup viewGroup = (ViewGroup) parent;    final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);    rInflate(parser, view, attrs, true);    viewGroup.addView(view, params);   }  }  if (finishInflate) parent.onFinishInflate();//解析完了,这个方法我们自定义可以复写 可以会去掉 子View的信息 } 
基本上布局都是ViewGroup的子类 里面都有child view, 我们常用的findViewById 就是遍历去找对应ID的View public final View findViewById(int id) {  if (id < 0) {   return null;  }  return findViewTraversal(id); } 直接看ViewGroup中的findViewTraversal @Override protected View findViewTraversal(int id) {   if (id == mID) { //等于自己   return this;  }  final View[] where = mChildren;  final int len = mChildrenCount;  for (int i = 0; i < len; i++) {   View v = where[i];   if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) { //IS_ROOT_NAMESPACE 可能是查询到最后一层了(猜的)  然后再遍历 查询    v = v.findViewById(id);    if (v != null) {     return v;    }   }  }  return null; } 

如果布局层级太深 解析XML和查找View都是耗费CPU的,所以做项目过程中 有必要进行布局优化。

本文源码: 4.1

正文到此结束
Loading...