關(guān)于LayoutInflater的用法

廢話不多說,直接上代碼:

常用的:

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

是不是經(jīng)常用這種方式來讀取xml,生成view.
如果你點(diǎn)開源碼去看就會知道,調(diào)用的其實(shí)是LayoutInflater

public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 
   LayoutInflater factory = LayoutInflater.from(context); //這里需要一個(gè)上下文
   return factory.inflate(resource, root);//調(diào)用的是LayoutInflater的inflate方法.
}

為什么要傳入一個(gè)上下文呢?

public static layoufrom(Context context) { 
//context.getSystemService,這不是activity里獲取系統(tǒng)服務(wù)類的方法么.
//看看介紹LAYOUT_INFLATER_SERVICE   LayoutInflater   取得xml里定義的view
   LayoutInflater LayoutInflater =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
   if (LayoutInflater == null) { //如果拿不到這個(gè)服務(wù)類就會拋出異常.
      throw new AssertionError("LayoutInflater not found."); 
   }   
   return LayoutInflater;
}

可以看出,LayoutInflater,其實(shí)是通過context 的getSystemService獲取到的系統(tǒng)服務(wù)對象.

接著往下看,查源碼,一路找到contextImpl類,這是抽象類context的實(shí)現(xiàn)類

系統(tǒng)關(guān)鍵代碼:

//這里可以理解為一種單例模式,通過hashmap來保存多個(gè)單例,并通過key,來獲取相應(yīng)的單例
//但是這里并不是直接保存單例,而保存了生成單例的對應(yīng)工廠.
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)) { 
       //將初始化時(shí)的順序賦值給ServiceFetcher中的mContextCacheIndex
       fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;  
  } 
    //將生成的ServiceFetcher工廠保存起來.
    SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
}
//通過靜態(tài)代碼塊,創(chuàng)建覆蓋了createService()方法的ServiceFetcher工廠來綁定對應(yīng)的系統(tǒng)服務(wù).
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) {   
    //通過名字拿到對應(yīng)的工廠,來獲取對應(yīng)的服務(wù)對象
     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. */
  //上面注釋的大概意思是,如果不需要緩存,就復(fù)寫這個(gè)方法.
   public Object getService(ContextImpl ctx) {   
      //ContextImpl中的service緩存集合
        ArrayList<Object> cache = ctx.mServiceCache;  
        Object service;  
        synchronized (cache) { 
           if (cache.size() == 0) {  //如果沒有緩存,則添加sNextPerContextServiceCacheIndex數(shù)量的長度.
               for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {      
               cache.add(null);     
             } else {   
                //如果有緩存,則通過該工廠保存的mContextCacheIndex角標(biāo)從contextImpl的cache中拿到service
                 service = cache.get(mContextCacheIndex); 
                 if (service != null) {  //不為null就直接返回
                 return service;      
             }  
         }  
    //如果為null,則調(diào)用這個(gè)工廠的生成方法,來生成對應(yīng)的系統(tǒng)服務(wù)
     //就通過靜態(tài)代碼塊里面,重寫了createService方法的匿名類來獲取
     service = createService(ctx);   
    //這里通過代碼塊里面的生成順序,來緩存service
     cache.set(mContextCacheIndex, service);  
    //返回我們需要的service
     return service;   
     }
  }
}

扯遠(yuǎn)了..

通過這塊內(nèi)容

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

可以看到是通過PolicyManager來獲取LayoutInflater實(shí)例的
接著看下去

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

這里IPolicy 是個(gè)接口,而sPolicy是通過反射生成的

PolicyManager主要用于創(chuàng)建Window類普舆、LayoutInflater類和WindowManagerPolicy類,它扮演著簡單工廠模式中的工廠類角色涝缝,而抽象產(chǎn)品角色由IPolicy接口實(shí)現(xiàn)腔剂,具體產(chǎn)品角色由Policy類實(shí)現(xiàn)谢鹊。

源碼就寫這些...

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

看看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.發(fā)現(xiàn)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的根節(jié)點(diǎn)為merge,則root不能為null,否則拋出異常
       //2.如果根節(jié)點(diǎn)為blink,則生成BlinkLayout作為根布局
       //3.如果1,2不成立,則根據(jù)根節(jié)點(diǎn)名稱,生成對應(yīng)的根布局
        if (TAG_1995.equals(name)) { //TAG_1995 ="blink";
           temp = new BlinkLayout(mContext, attrs);
        } else {
            temp = createViewFromTag(root, name, attrs);
        }
       //4.如果root不為null,則拿到root的layoutparams,來設(shè)置根布局的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;  //返回解析出來的
  }}

總結(jié):

舉例:

//例1.生成view,但不指定父容器,如果父容器為null,那么設(shè)置ture還是false結(jié)果都一樣
LayoutInflater.from(context).inflate(id,null);
//例2.結(jié)果和1一樣,
LayoutInflater.from(context).inflate(id,null,false);
//例3.結(jié)果和1一樣
LayoutInflater.from(context).inflate(id,null,true);
//例4.生成view,指定父容器,并添加到其中,獲取parent的Layoutparmas設(shè)置view的Layoutparmas.
LayoutInflater.from(context).inflate(id,parent,true);
//例5.生成view,指定父容器,不添加到其中,獲取parent的Layoutparmas設(shè)置view的Layoutparmas.
LayoutInflater.from(context).inflate(id,parent,false);

用例1,2,3生成的view是沒有Layoutparmas的.所以必須手動設(shè)置,不然xml里面設(shè)置的屬性會失效

用例4,5設(shè)生成的view,不管設(shè)置的true還是false,生成的view都會從parent中得到Layoutparmas
,區(qū)別在于,是否添加到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().

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蚓再,更是在濱河造成了極大的恐慌只损,老刑警劉巖一姿,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異跃惫,居然都是意外死亡叮叹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進(jìn)店門爆存,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衬横,“玉大人,你說我怎么就攤上這事终蒂》淞郑” “怎么了?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵拇泣,是天一觀的道長噪叙。 經(jīng)常有香客問我,道長霉翔,這世上最難降的妖魔是什么睁蕾? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮债朵,結(jié)果婚禮上子眶,老公的妹妹穿的比我還像新娘。我一直安慰自己序芦,他們只是感情好臭杰,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谚中,像睡著了一般渴杆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宪塔,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天磁奖,我揣著相機(jī)與錄音,去河邊找鬼某筐。 笑死比搭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的南誊。 我是一名探鬼主播身诺,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼蔽莱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了戚长?” 一聲冷哼從身側(cè)響起盗冷,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎同廉,沒想到半個(gè)月后仪糖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡迫肖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年锅劝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蟆湖。...
    茶點(diǎn)故事閱讀 38,683評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡故爵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出隅津,到底是詐尸還是另有隱情诬垂,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布伦仍,位于F島的核電站结窘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏充蓝。R本人自食惡果不足惜隧枫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谓苟。 院中可真熱鬧官脓,春花似錦、人聲如沸涝焙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纱皆。三九已至湾趾,卻和暖如春芭商,著一層夾襖步出監(jiān)牢的瞬間派草,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工铛楣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留近迁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓簸州,卻偏偏與公主長得像鉴竭,于是被迫代替她去往敵國和親歧譬。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理搏存,服務(wù)發(fā)現(xiàn)瑰步,斷路器,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • 用法獲取LayoutInflater 首先要注意LayoutInflater本身是一個(gè)抽象類璧眠,我們不可以直接通過n...
    我本和圖閱讀 867評論 0 0
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程缩焦,因...
    小菜c閱讀 6,367評論 0 17
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,773評論 6 342
  • 一、適用場景 ListViewListview是一個(gè)很重要的組件责静,它以列表的形式根據(jù)數(shù)據(jù)的長自適應(yīng)展示具體內(nèi)容,用...
    Geeks_Liu閱讀 10,654評論 1 28