关于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<String, ServiceFetcher> SYSTEM_SERVICE_MAP =  new HashMap<String, ServiceFetcher>();
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<Object> 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().

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,233评论 6 495
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,357评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,831评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,313评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,417评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,470评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,482评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,265评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,708评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,997评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,176评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,503评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,150评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,391评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,034评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,063评论 2 352

推荐阅读更多精彩内容