LayoutInflater源碼解析,layoutinflater源碼

來源:互聯網
上載者:User

LayoutInflater源碼解析,layoutinflater源碼

Android使用LayoutInflater來進行布局載入,通常擷取方式有兩種:

第一種:

LayoutInflater layoutInflater = LayoutInflater.from(context); 

第二種:

LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

從源碼中可以看出第一種是第二種的封裝簡化,便於使用:

1 public static LayoutInflater from(Context context) {2         LayoutInflater LayoutInflater =3                 (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);4         if (LayoutInflater == null) {5             throw new AssertionError("LayoutInflater not found.");6         }7         return LayoutInflater;8     }

我們通過調用inflate方法便可以完成對布局的載入:

layoutInflater.inflate(resource, root, true);  

LayoutInflater中的inflate方法有若干種重載方式,最終都調用了如下代碼:

  1 public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {  2         synchronized (mConstructorArgs) {  3             //擷取xml中屬性資訊  4             final AttributeSet attrs = Xml.asAttributeSet(parser);  5             Context lastContext = (Context)mConstructorArgs[0];  6             mConstructorArgs[0] = mContext;  7             View result = root;  8   9             try { 10                 // 尋找根節點. 11                 int type; 12                 while ((type = parser.next()) != XmlPullParser.START_TAG && 13                         type != XmlPullParser.END_DOCUMENT) { 14                     // Empty 15                 } 16                  17                 if (type != XmlPullParser.START_TAG) { 18                     throw new InflateException(parser.getPositionDescription() 19                             + ": No start tag found!"); 20                 } 21                 //擷取根節點名稱 22                 final String name = parser.getName(); 23                  24                 if (DEBUG) { 25                     System.out.println("**************************"); 26                     System.out.println("Creating root view: " 27                             + name); 28                     System.out.println("**************************"); 29                 } 30                 //如果是merge標籤,必須保證父節點不為null且attachToRoot為true 31                 if (TAG_MERGE.equals(name)) { 32                     if (root == null || !attachToRoot) { 33                         throw new InflateException("<merge /> can be used only with a valid " 34                                 + "ViewGroup root and attachToRoot=true"); 35                     } 36  37                     rInflate(parser, root, attrs, false); 38                 } else { 39                     //代表布局檔案中根節點的view 40                     View temp; 41                     if (TAG_1995.equals(name)) { 42                         temp = new BlinkLayout(mContext, attrs); 43                     } else { 44                         //利用反射,通過root名稱建立view 45                         temp = createViewFromTag(root, name, attrs); 46                     } 47  48                     ViewGroup.LayoutParams params = null; 49  50                     if (root != null) { 51                         if (DEBUG) { 52                             System.out.println("Creating params from root: " + 53                                     root); 54                         } 55                         // Create layout params that match root, if supplied 56                         //當提供了父容器時,由父容器根據屬性值建立布局參數 57                         params = root.generateLayoutParams(attrs); 58                         if (!attachToRoot) { 59                             // Set the layout params for temp if we are not 60                             // attaching. (If we are, we use addView, below) 61                             //當不把當前view附加到父容器中,則設定擷取到的布局參數 62                            //否則使用下面的addView方法設定 63                             temp.setLayoutParams(params); 64                         } 65                     } 66  67                     if (DEBUG) { 68                         System.out.println("-----> start inflating children"); 69                     } 70                     // Inflate all children under temp 71                    //遞迴調用此方法載入子布局 72                     rInflate(parser, temp, attrs, true); 73                     if (DEBUG) { 74                         System.out.println("-----> done inflating children"); 75                     } 76  77                     // We are supposed to attach all the views we found (int temp) 78                     // to root. Do that now. 79                     if (root != null && attachToRoot) { 80                         root.addView(temp, params); 81                     } 82  83                     // Decide whether to return the root that was passed in or the 84                     // top view found in xml. 85                     if (root == null || !attachToRoot) { 86                         result = temp; 87                     } 88                 } 89  90             } catch (XmlPullParserException e) { 91                 InflateException ex = new InflateException(e.getMessage()); 92                 ex.initCause(e); 93                 throw ex; 94             } catch (IOException e) { 95                 InflateException ex = new InflateException( 96                         parser.getPositionDescription() 97                         + ": " + e.getMessage()); 98                 ex.initCause(e); 99                 throw ex;100             } finally {101                 // Don't retain static reference on context.102                 mConstructorArgs[0] = lastContext;103                 mConstructorArgs[1] = null;104             }105 106             return result;107         }108     }

這裡,Android使用了PULL來解析xml布局檔案,並通過反射來建立出當前view:

temp = createViewFromTag(root, name, attrs);

 

我們查看一下源碼:

 1 View createViewFromTag(View parent, String name, AttributeSet attrs) { 2         if (name.equals("view")) { 3             name = attrs.getAttributeValue(null, "class"); 4         } 5  6         if (DEBUG) System.out.println("******** Creating view: " + name); 7  8         try { 9             View view;10             if (mFactory2 != null) view = mFactory2.onCreateView(parent, name, mContext, attrs);11             else if (mFactory != null) view = mFactory.onCreateView(name, mContext, attrs);12             else view = null;13 14             if (view == null && mPrivateFactory != null) {15                 view = mPrivateFactory.onCreateView(parent, name, mContext, attrs);16             }17             18             if (view == null) {19                 if (-1 == name.indexOf('.')) {20                     view = onCreateView(parent, name, attrs);21                 } else {22                     view = createView(name, null, attrs);23                 }24             }25 26             if (DEBUG) System.out.println("Created view is: " + view);27             return view;28 29         } catch (InflateException e) {30             throw e;31 32         } catch (ClassNotFoundException e) {33             InflateException ie = new InflateException(attrs.getPositionDescription()34                     + ": Error inflating class " + name);35             ie.initCause(e);36             throw ie;37 38         } catch (Exception e) {39             InflateException ie = new InflateException(attrs.getPositionDescription()40                     + ": Error inflating class " + name);41             ie.initCause(e);42             throw ie;43         }44     }

裡面根據不同情況,調用了onCreateView方法,利用反射來建立view。其中可以使用指定的factory來建立view,這樣的鉤子設計使得inflate方法變得十分靈活。

然後調用rInflate(parser, temp, attrs, true)方法來遞迴尋找temp中的子view,並添加到上層view中:

 1 void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs, 2             boolean finishInflate) throws XmlPullParserException, IOException { 3  4         final int depth = parser.getDepth(); 5         int type; 6  7         while (((type = parser.next()) != XmlPullParser.END_TAG || 8                 parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { 9 10             if (type != XmlPullParser.START_TAG) {11                 continue;12             }13 14             final String name = parser.getName();15             16             if (TAG_REQUEST_FOCUS.equals(name)) {17                 parseRequestFocus(parser, parent);18             } else if (TAG_INCLUDE.equals(name)) {19                 if (parser.getDepth() == 0) {20                     throw new InflateException("<include /> cannot be the root element");21                 }22                 parseInclude(parser, parent, attrs);23             } else if (TAG_MERGE.equals(name)) {24                 throw new InflateException("<merge /> must be the root element");25             } else if (TAG_1995.equals(name)) {26                 final View view = new BlinkLayout(mContext, attrs);27                 final ViewGroup viewGroup = (ViewGroup) parent;28                 final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);29                 rInflate(parser, view, attrs, true);30                 viewGroup.addView(view, params);                31             } else {32                 final View view = createViewFromTag(parent, name, attrs);33                 final ViewGroup viewGroup = (ViewGroup) parent;34                 final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);35                 rInflate(parser, view, attrs, true);36                 viewGroup.addView(view, params);37             }38         }39 40         if (finishInflate) parent.onFinishInflate();41     }

裡面也用到onCreateView方法建立子view,然後將其加入到父view中返回。

通過查看上面的源碼,我們可以發現inflate方法中的三個參數int resource, ViewGroup root, boolean attachToRoot的作用如下:

resource指定了要載入的view,root作為view外面一層的父容器,attachToRoot表示是否將view加入到父容器。

當指定了父容器,並且attachToRoot為true,則將view加入到父容器中。

如果指定了父容器,卻將attachToRoot設定為false,那麼只是從父容器中產生了view布局的參數並設定給view

當未指定父容器時,直接返回view本身。

 

總結

通過研究LayoutInflater源碼的設計,我們瞭解到代碼的執行細節的同時,也可以發現:

LayoutInflater建立view對象時候使用了簡單原廠模式,並通過加入鉤子方法,利用抽象原廠模式讓coder可以使用自訂的Factory 方法來建立view。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.