Android View 原始碼解析(二) - LayoutInflater
繼 Android View 原始碼解析(一) - setContentView 之後接著說
之前我們分析了setContentView方法的相關程式碼 接下來說說LayoutInflater的方法
LayoutInflater原始碼分析
- 與setContentView相關
在PhoneWindow的generateLayout中呼叫了
View in = mLayoutInflater.inflate(layoutResource, null);
- LayoutInflater中獲取例項化方法
/** * Obtains the LayoutInflater from the given context. */ 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; }
- inflate方法相關
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) { return inflate(resource, root, root != null); } public View inflate(XmlPullParser parser, @Nullable ViewGroup root) { return inflate(parser, root, root != null); }
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) { final Resources res = getContext().getResources(); if (DEBUG) { Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" (" + Integer.toHexString(resource) + ")"); } final XmlResourceParser parser = res.getLayout(resource); try { return inflate(parser, root, attachToRoot); } finally { parser.close(); } }
最後發現都需要呼叫
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) { synchronized (mConstructorArgs) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate"); final Context inflaterContext = mContext; final AttributeSet attrs = Xml.asAttributeSet(parser); Context lastContext = (Context) mConstructorArgs[0]; mConstructorArgs[0] = inflaterContext; //定義返回值 初始化傳入形參 root View result = root; try { // 找到根節點 int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { } //驗證type是否為Start_Tag保證xml檔案正確 if (type != XmlPullParser.START_TAG) { throw new InflateException(parser.getPositionDescription() + ": No start tag found!"); } //type為 root node final String name = parser.getName(); if (DEBUG) { System.out.println("**************************"); System.out.println("Creating root view: " + name); System.out.println("**************************"); } if (TAG_MERGE.equals(name)) { //處理 merge相關 //root需要非空 且attachToRoot為空 if (root == null || !attachToRoot) { throw new InflateException("<merge /> can be used only with a valid " + "ViewGroup root and attachToRoot=true"); } //遞迴inflate 方法呼叫 rInflate(parser, root, inflaterContext, attrs, false); } else { //根據tag節點建立view物件 final View temp = createViewFromTag(root, name, inflaterContext, attrs); ViewGroup.LayoutParams params = null; if (root != null) { if (DEBUG) { System.out.println("Creating params from root: " + root); } //根據root生成LayoutParams params = root.generateLayoutParams(attrs); if (!attachToRoot) { //如果attachToRoot為flase 則呼叫setLayoutParams temp.setLayoutParams(params); } } if (DEBUG) { System.out.println("-----> start inflating children"); } //遞迴inflate剩下的children rInflateChildren(parser, temp, attrs, true); if (DEBUG) { System.out.println("-----> done inflating children"); } // We are supposed to attach all the views we found (int temp) // to root. Do that now. if (root != null && attachToRoot) { //root非空且attachToRoot=true則將xml檔案的root view加到形參提供的root裡 root.addView(temp, params); } // Decide whether to return the root that was passed in or the // top view found in xml. if (root == null || !attachToRoot) { //返回xml裡解析的root view result = temp; } } } catch (XmlPullParserException e) { InflateException ex = new InflateException(e.getMessage()); ex.initCause(e); throw ex; } catch (Exception e) { InflateException ex = new InflateException( parser.getPositionDescription() + ": " + e.getMessage()); ex.initCause(e); throw ex; } finally { // Don't retain static reference on context. mConstructorArgs[0] = lastContext; mConstructorArgs[1] = null; } Trace.traceEnd(Trace.TRACE_TAG_VIEW); //返回引數root或xml檔案裡的root view return result; } }
相關inflate引數的結果

-
相關方法解析
在Inflate中多次被呼叫的rInflate
void rInflate(XmlPullParser parser, View parent, Context context, AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException { final int depth = parser.getDepth(); int type; //XmlPullParser解析器的標準解析模式 while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { //找到start_tag節點 if (type != XmlPullParser.START_TAG) { continue; } //獲取Name標記 final String name = parser.getName(); //private static final String TAG_REQUEST_FOCUS = "requestFocus"; //處理requestFocus if (TAG_REQUEST_FOCUS.equals(name)) { parseRequestFocus(parser, parent); // private static final String TAG_TAG = "tag"; //處理tag } else if (TAG_TAG.equals(name)) { parseViewTag(parser, parent, attrs); //private static final String TAG_INCLUDE = "include"; //處理include } else if (TAG_INCLUDE.equals(name)) { //如果是根節點則丟擲異常 if (parser.getDepth() == 0) { throw new InflateException("<include /> cannot be the root element"); } parseInclude(parser, context, parent, attrs); //private static final String TAG_MERGE = "merge"; //處理merge merge需要是xml中的根節點 } else if (TAG_MERGE.equals(name)) { throw new InflateException("<merge /> must be the root element"); } else { final View view = createViewFromTag(parent, name, context, attrs); final ViewGroup viewGroup = (ViewGroup) parent; final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs); rInflateChildren(parser, view, attrs, true); viewGroup.addView(view, params); } } //parent的所有子節點都處理完畢的時候回onFinishInflate方法 if (finishInflate) { parent.onFinishInflate(); } } //可以新增自定義邏輯 protected void onFinishInflate() { }
【附錄】

資料圖
需要資料的朋友可以加入Android架構交流QQ群聊:513088520
點選連結加入群聊【Android移動架構總群】: 加入群聊
獲取免費學習視訊,學習大綱另外還有像高階UI、效能優化、架構師課程、NDK、混合式開發(ReactNative+Weex)等Android高階開發資料免費分享。