Android Layoutinflater.from (). Inflate () source parsing

Source: Internet
Author: User

We know that Phonewindow#setcontentview () is called in Activity#setcontentview (). and in Phonewindow#setcontentview () there is a sentence mLayoutInflater.inflate(layoutResID, mContentParent) . The purpose of this line of code is to fill our activity_main.xml into the mcontentparent. See: Setcontentview source parsing. When writing adapter, also often write mInflater.inflate(layoutResID, null) . So how does this line of code convert an XML file into a view or viewgroup?

There are two ways to get the Layoutinflater object:

    1. LayoutInflater.from(Context context);
    2. LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

Actually these two are the same way, first look at the Layoutinflater#from ()

SOURCE Location: Frameworks/base/core/java/android/view/layoutinflater.java

Layoutinflater#from ()

    publicstaticfrom(Context context) {        LayoutInflater LayoutInflater =                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);        ifnull) {            thrownew AssertionError("LayoutInflater not found.");        }        return LayoutInflater;    }

The first way to get a Layoutinflater object is a simple encapsulation of the second way. It's actually the same thing. The implementation class of the context is Contextimpl, follow-up.

SOURCE Location: Frameworks/base/core/java/android/app/contextimpl.java

Contextimpl#getsystemservice ()

    @Override    publicgetSystemService(String name) {        return SystemServiceRegistry.getSystemService(this, name);    }

Follow.

SOURCE Location: Frameworks/base/core/java/android/app/systemserviceregistry.java

Systemserviceregistry#getsystemservice ()

    publicstaticgetSystemService(ContextImpl ctx, String name) {        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);        returnnullnull;    }

Get to fetcher directly from the global variable system_service_fetchers by name, followed by Fetcher Direct get to the Layoutinflater object. Capitalize on the b~ of the original Ah, in the systemserviceregistry there is a static code block, first look at this part.

    Static{... registerservice (Context.layout_inflater_service, Layoutinflater.class,NewCachedservicefetcher<layoutinflater> () {@Override             PublicLayoutinflaterCreateService(Contextimpl CTX) {return NewPhonelayoutinflater (Ctx.getoutercontext ());        }}); ...    }Private Static<T>void Registerservice(String serviceName, class<t> serviceclass, servicefetcher<t> servicefetcher)        {System_service_names.put (ServiceClass, serviceName);    System_service_fetchers.put (ServiceName, Servicefetcher); }Static AbstractClass Cachedservicefetcher<t> implements Servicefetcher<t> {Private Final intMcacheindex; Public Cachedservicefetcher() {mcacheindex = sservicecachesize++; }@Override        @SuppressWarnings("Unchecked") Public FinalTGetService(Contextimpl CTX) {Finalobject[] cache = Ctx.mservicecache;synchronized(cache) {//Fetch or create the service.Object service = Cache[mcacheindex];if(Service = =NULL) {service = CreateService (CTX);                Cache[mcacheindex] = Service; }return(T) Service; }        } Public AbstractTCreateService(Contextimpl CTX); }

There are two successive methods and an abstract inner class cachedservicefetcher. Since the phonelayoutinflater is returned in the concrete implementation of the abstract method Cachedservicefetcher#createservice (), the object used in the following article is always phonelayoutinflater. After getting the Layoutinflater object (which is actually its subclass Phonelayoutinflater object), call Layoutinflater#inflate (). Follow.

SOURCE Location: Frameworks/base/core/java/android/view/layoutinflater.java

Layoutinflater#inflate ()

    publicinflateint resource, @Nullable ViewGroup root) {        returnnull);    }

Here is an example of Setcontentview, which in mLayoutInflater.inflate(layoutResID, mContentParent) passing will also explain mInflater.inflate(layoutResID,null) the situation in adapter. That is root , the parameters are null and not null two cases. , the third parameter is root==null false . root!=null , and the third argument is true . Follow.

Layoutinflater#inflate ()

    publicinflateintboolean attachToRoot) {        final Resources res = getContext().getResources();        final XmlResourceParser parser = res.getLayout(resource);        try {            return inflate(parser, root, attachToRoot);        finally {            parser.close();        }    }

Follow.

Layoutinflater#inflate ()

Public View Inflate (xmlpullparser parser, @Nullable ViewGroup root, Boolean attachtoroot) {synchronized (Mconstruc Torargs) {...View result = root;Try{...Gets the string of the root node, such as LinearLayout final string name = Parser.getname (); Root node Merge startif(tag_merge.equals (name)) {...}Else{//Create root view, view Final View temp = Createviewfromtag (root, Name, Inflatercontext, attr                    s); Viewgroup.layoutparams params = null;if(root = null) {//get layoutparams params = Root.generatelayoutparams (attrs);if(!attachtoroot)                        {//apply Layoutparams to root node view temp.setlayoutparams (params); }}//Traverse parse child view and add to root node temp in Rinflatechildren (pars                    Er, temp, attrs, true); Root is not empty, add root view directly to rootif(root = null && attachtoroot)                    {Root.addview (temp, params); }//root equals null, return directly to root node tempif(Root = null | |!attachtoroot)                    {result = temp; }}}catch (Exception e) {...}returnResult }    }

There are comments on each of the above steps, and the following highlights the Createviewfromtag () and the Rinflatechildren () method that generates the view of the root node and iterates through the generated sub-view.

Layoutinflater#createviewfromtag ()

    private View createViewFromTag(View parent, String name, Context context, AttributeSet attrs) {        return createViewFromTag(parent, name, context, attrs, false);    }    View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,            boolean ignoreThemeAttr) {        ...        if (-1 == name.indexOf(‘.‘)) {            view = onCreateView(parent, name, attrs);        else {            view = createView(name, null, attrs);        }        ...        return view;    }

Follow.

Layoutinflater#createview ()

Public final View CreateView (string name, string prefix, AttributeSet attrs) throws ClassNotFoundException, INF        lateexception {constructor<? extends view> Constructor = sconstructormap.get (name); class<? Extends view> clazz = null;Try{if(constructor = = null) {clazz = Mcontext.getclassloader (). loadclass (prefix! = null?) (prefix + name): name). Assubclass (View.class);...constructor = Clazz.getconstructor (mconstructorsignature);                Constructor.setaccessible (TRUE);            Sconstructormap.put (name, constructor); }Else{...Final View view = Constructor.newinstance (args);returnView } catch (Exception e) {...}       }

Sconstructormap is an HashMap<String, Constructor<? extends View>> object. The first is based on the name of the root node, for example, LinearLayout to find the cached constructor, and if it is executed for the first time, it is definitely returned null . If returned as null , the construction method is reflected by reflection, and the setting is forced to be accessible and then saved into the Sconstructormap. If there is a constructor in the cache, take it out directly. The last call newInstance reflects the root node view instance. After the root node view instance is obtained, the properties are set, and finally the Rinflatechildren () traversal is called to create the child view. Follow.

Layoutinflater#rinflatechildren ()

    finalvoid rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,            booleanthrows XmlPullParserException, IOException {        rInflate(parser, parent, parent.getContext(), attrs, finishInflate);    }

parentThe parameter is the root node view. Here is simply a transfer to the Rinflate () method processing. Follow.

Layoutinflater#rinflatechildren ()

void Rinflate (Xmlpullparser parser, View Parent, context context, AttributeSet Attrs, boolean finishinflate) th        Rows Xmlpullparserexception, IOException {final int depth = parser.getdepth (); int type; while((type = Parser.next ())! = Xmlpullparser.end_tag | | Parser.getdepth () > Depth) && type! = xmlpullparser.end_document) {if(Type! = Xmlpullparser.start_tag)            {continue; } final String name = Parser.getname ();if(tag_request_focus.equals (name)) {...}...}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); }        }if(finishinflate)        {parent.onfinishinflate (); }    }

Traversal is the While name of the child node view, such as Textview,relativelayout, which is reflected on the loop. Several sub-nodes that start with tag, include, and so on, take the logic of the top few if, and our focus is on the else logic of the ordinary view walk. Can see: First, and create the root node view call the same method Createviewfromtag () Create a child view, and then set the parameters of the child view, and then call the recursive call Rinflatechildren () method to measure the child node all view, Finally, the child node is added to the parent layout, which may be the root node or a child node. After the traversal is complete, all child view is added to the layout and the corresponding layout parameters are set.

At this point, Layoutinflater.from (). Inflate () source parsing end ~

More framework source code Analysis, please visit the framework Source code parsing series [catalog]

Android Layoutinflater.from (). Inflate () source parsing

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.