关于LayoutInflater的用法

废话不多说,直接上代码:

常用的:

View inflate = View.inflate(context, resource, null);

是不是经常用这种方式来读取xml,生成view.
如果你点开源码去看就会知道,调用的其实是LayoutInflater

public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 
   LayoutInflater factory = LayoutInflater.from(context); //这里需要一个上下文
   return factory.inflate(resource, root);//调用的是LayoutInflater的inflate方法.
}

为什么要传入一个上下文呢?

public static layoufrom(Context context) { 
//context.getSystemService,这不是activity里获取系统服务类的方法么.
//看看介绍LAYOUT_INFLATER_SERVICE   LayoutInflater   取得xml里定义的view
   LayoutInflater LayoutInflater =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
   if (LayoutInflater == null) { //如果拿不到这个服务类就会抛出异常.
      throw new AssertionError("LayoutInflater not found."); 
   }   
   return LayoutInflater;
}

可以看出,LayoutInflater,其实是通过context 的getSystemService获取到的系统服务对象.

接着往下看,查源码,一路找到contextImpl类,这是抽象类context的实现类

系统关键代码:

//这里可以理解为一种单例模式,通过hashmap来保存多个单例,并通过key,来获取相应的单例
//但是这里并不是直接保存单例,而保存了生成单例的对应工厂.
private static final HashMap SYSTEM_SERVICE_MAP =  new HashMap();
private static int sNextPerContextServiceCacheIndex = 0;
private static void registerService(String serviceName, ServiceFetcher fetcher) { 
   if (!(fetcher instanceof StaticServiceFetcher)) { 
       //将初始化时的顺序赋值给ServiceFetcher中的mContextCacheIndex
       fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;  
  } 
    //将生成的ServiceFetcher工厂保存起来.
    SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
}
//通过静态代码块,创建覆盖了createService()方法的ServiceFetcher工厂来绑定对应的系统服务.
static {
      registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {  
      public Object createService(ContextImpl ctx) { 
           return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());  
      }});
      //很多registerService(String serviceName, ServiceFetcher fetcher);
      .......
}
@Override
public Object getSystemService(String name) {   
    //通过名字拿到对应的工厂,来获取对应的服务对象
     ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);   
      return fetcher == null ? null : fetcher.getService(this);
}
static class ServiceFetcher { 
   int mContextCacheIndex = -1;
   /** * Main entrypoint; only override if you don't need caching. */
  //上面注释的大概意思是,如果不需要缓存,就复写这个方法.
   public Object getService(ContextImpl ctx) {   
      //ContextImpl中的service缓存集合
        ArrayList cache = ctx.mServiceCache;  
        Object service;  
        synchronized (cache) { 
           if (cache.size() == 0) {  //如果没有缓存,则添加sNextPerContextServiceCacheIndex数量的长度.
               for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {      
               cache.add(null);     
             } else {   
                //如果有缓存,则通过该工厂保存的mContextCacheIndex角标从contextImpl的cache中拿到service
                 service = cache.get(mContextCacheIndex); 
                 if (service != null) {  //不为null就直接返回
                 return service;      
             }  
         }  
    //如果为null,则调用这个工厂的生成方法,来生成对应的系统服务
     //就通过静态代码块里面,重写了createService方法的匿名类来获取
     service = createService(ctx);   
    //这里通过代码块里面的生成顺序,来缓存service
     cache.set(mContextCacheIndex, service);  
    //返回我们需要的service
     return service;   
     }
  }
}
 
 

扯远了..

通过这块内容

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

可以看到是通过PolicyManager来获取LayoutInflater实例的
接着看下去

private static final IPolicy sPolicy;
..........
public static LayoutInflater makeNewLayoutInflater(Context context) { 
   return sPolicy.makeNewLayoutInflater(context);
}

这里IPolicy 是个接口,而sPolicy是通过反射生成的

PolicyManager主要用于创建Window类、LayoutInflater类和WindowManagerPolicy类,它扮演着简单工厂模式中的工厂类角色,而抽象产品角色由IPolicy接口实现,具体产品角色由Policy类实现。

源码就写这些...

------------------------

看看LayoutInflater用法:

//1.传入xml的解析,父容器,用的较少
public View inflate(XmlPullParser parser, ViewGroup root) { 
   return inflate(parser, root, root != null);
}
//2.传入资源Id.与父容器,走到方法3
public View inflate(int resource, ViewGroup root) { 
  return inflate(resource, root, root != null);
}
//3.传入资源Id.与父容器,是否加载到父容器,用的较多
public View inflate(int resource, ViewGroup root, boolean attachToRoot) { 
   if (DEBUG) System.out.println("INFLATING from resource: " + resource);  
  XmlResourceParser parser = getContext().getResources().getLayout(resource);   
 try {   
      //传入xml的解析,父容器,是否直接添加到父t容器
     return inflate(parser, root, attachToRoot);   
   } finally {   
     parser.close(); 
  }}
//4.发现1,2,3,最终都是走到这里
/**
*    parser xml资源
*    root  父容器
*    attachToRoot  是否直接加载到父容器中
**/
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
    synchronized (mConstructorArgs) { 
           Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");    
          final AttributeSet attrs = Xml.asAttributeSet(parser);     
           Context lastContext = (Context)mConstructorArgs[0];    
          mConstructorArgs[0] = mContext;      
         View result = root;      
  try {      
       //解析xml,代码较多,部分代码省略
       //1.如果xml的根节点为merge,则root不能为null,否则抛出异常
       //2.如果根节点为blink,则生成BlinkLayout作为根布局
       //3.如果1,2不成立,则根据根节点名称,生成对应的根布局
        if (TAG_1995.equals(name)) { //TAG_1995 ="blink";
           temp = new BlinkLayout(mContext, attrs);
        } else {
            temp = createViewFromTag(root, name, attrs);
        }
       //4.如果root不为null,则拿到root的layoutparams,来设置根布局的layoutparams.
          if (root != null) {  
               params = root.generateLayoutParams(attrs);   
               if (!attachToRoot) {  
                      temp.setLayoutParams(params);  
               }
        }
       //5.通过解析出的根布局,然后解析其包含的所有子控件.
            rInflate(parser, temp, attrs, true);
      //6.如果传入的root不为null并且attachToRoot为true,则将解析出来的view添加到root容器中
            if (root != null && attachToRoot) { 
                root.addView(temp, params);
          }
      //7.如果传入的root为null或者attachToRoot为false,则不添加
      if (root == null || !attachToRoot) {  
          result = temp;
      }
      } finally { 
           // Don't retain static reference on context.   
           mConstructorArgs[0] = lastContext;       
           mConstructorArgs[1] = null;     
       }    
     Trace.traceEnd(Trace.TRACE_TAG_VIEW);   
     return result;  //返回解析出来的
  }}

总结:

举例:

//例1.生成view,但不指定父容器,如果父容器为null,那么设置ture还是false结果都一样
LayoutInflater.from(context).inflate(id,null);
//例2.结果和1一样,
LayoutInflater.from(context).inflate(id,null,false);
//例3.结果和1一样
LayoutInflater.from(context).inflate(id,null,true);
//例4.生成view,指定父容器,并添加到其中,获取parent的Layoutparmas设置view的Layoutparmas.
LayoutInflater.from(context).inflate(id,parent,true);
//例5.生成view,指定父容器,不添加到其中,获取parent的Layoutparmas设置view的Layoutparmas.
LayoutInflater.from(context).inflate(id,parent,false);

用例1,2,3生成的view是没有Layoutparmas的.所以必须手动设置,不然xml里面设置的属性会失效

用例4,5设生成的view,不管设置的true还是false,生成的view都会从parent中得到Layoutparmas
,区别在于,是否添加到parent中

如果使用例4,则不要再去parent.addview(),否则会抛出异常

if (child.getParent() != null) {  
        throw new IllegalStateException(
    "The specified child already has a parent." 
    "You must call removeView() on the child's parent first.");
}

使用例5,则可以使用parent.addview().

你可能感兴趣的:(关于LayoutInflater的用法)