Android loading from XML to view object process parsing _android

Source: Internet
Author: User
Tags xml parser

We start with the activity of Setcontentview (), starting source analysis,

Activity.setcontentview public
void Setcontentview (int layoutresid) {
GetWindow (). Setcontentview ( LAYOUTRESID);
Initactionbar ();
}
Phonewindow.setcontentview public
void Setcontentview (int layoutresid) {
if (mcontentparent = = null) {
Installdecor ();
} else {
mcontentparent.removeallviews ();
}
Mlayoutinflater.inflate (Layoutresid, mcontentparent);
Final Callback cb = Getcallback ();
if (CB!= null &&!isdestroyed ()) {
cb.oncontentchanged ();
}
}

The discovery was made using Mlayoutinflater to create the view, so we went to the layoutinflater.inflate () and looked inside,

Public View Inflate (int resource, ViewGroup root, Boolean attachtoroot) {
if (DEBUG) System.out.println ("Inflating fr Om resource: "+ resource";
Xmlresourceparser parser = GetContext (). Getresources (). GetLayout (Resource);
try {return
inflate (parser, Root, attachtoroot);
} finally {
parser.close ();
}
}

First, according to the resource ID to get to the xmlresourceparseer, meaning as its name, is the XML parser, continue down, into the inflate core method, some long, we only analyze the key parts:

 public View Inflate (Xmlpullparser parser, ViewGroup root, Boolean attachtoroot) {... if (tag_merge.equals (name)) {if (root = null | |!attachtoroot) {throw new Inflateexception ("<merge/> can be use
D only with a valid "+" ViewGroup root and Attachtoroot=true ");}
Rinflate (parser, Root, attrs, false); else {//The temp is the root view, that's found in the XML view Temp. If (tag_1995.equals (name)) {temp = new blinklayout
(Mcontext, Attrs); else {temp = Createviewfromtag (root, name, attrs);} 
catch (Xmlpullparserexception e) {inflateexception ex = new Inflateexception (E.getmessage ()); Ex.initcause (e); throw ex; catch (IOException e) {inflateexception ex = new Inflateexception (parser.getpositiondescription () + ":" + E.getmessa
GE ());
Ex.initcause (e);
Throw ex; 
finally {//Don ' t retain static reference on context. Mconstructorargs[0] = Lastcontext; mconstructorargs[1] = null;}
return result; }
}

If tag's name is not tag_1995 (the name is a terrier), call the function Createviewfromtag () Create view, go in and see,

View Createviewfromtag (view parent, String name, AttributeSet attrs) {
if (name.equals ("View")) {
name = attrs.ge Tattributevalue (NULL, "class");
}
......
View view;
if (MFactory2!= null) view = Mfactory2.oncreateview (parent, name, Mcontext, attrs);
else if (mfactory!= null) view = Mfactory.oncreateview (name, Mcontext, attrs);
else view = null;
if (view = = null && mprivatefactory!= null) {
view = Mprivatefactory.oncreateview (parent, name, Mcontext, at TRS);
}
if (view = = null) {
if ( -1 = Name.indexof ('. ')) {
view = Oncreateview (parent, name, attrs);
} else {
view = CreateView (name, null, attrs);
}
}
if (DEBUG) System.out.println ("Created view is:" + view);
return view;
......
}

First try to create a view with 3 fractory, and return it directly if successful. Note that we can use this mechanism to create our own factory to control the view creation process.

If there is no factory or creation failure, go to default logic.

First determine if the name has '. ' Characters, if not, think of using Android's own view, which will then precede name with the package name "Android.view." If you have this '. ', then you think that the custom view you are using does not need to add any prefix to assume that name already contains the full package name.

Finally, use the name of the full package name to create the instance,

Private static final hashmap<string, constructor<? Extends view>> sconstructormap = new hashmap<string, constructor<?
Extends View>> (); Protected View Oncreateview (String name, AttributeSet attrs) throws ClassNotFoundException {return CreateView (name, "and
Roid.view. ", attrs); Public final View CreateView (string name, string prefix, AttributeSet attrs) throws ClassNotFoundException, Inflateexcep
tion {constructor< extends view> constructor = sconstructormap.get (name); class<?
   Extends view> clazz = null; ... if (constructor = null) {//Class not found in the cache, if it's real, and try to add it clazz = mcontext.ge Tclassloader (). loadclass (prefix!= null?
(prefix + name): name). Assubclass (View.class); if (mfilter!= null && clazz!= null) {Boolean allowed = Mfilter.onloadclass (clazz); if (!allowed) {Failnotallow
Ed (name, prefix, attrs);
} constructor = Clazz.getconstructor (mconstructorsignature); Sconstructormap.put (Name, constructor); else {//If we have a filter, apply it to cached constructor if (Mfilter!= null) {//Have we seen this name before? B
Oolean allowedstate = mfiltermap.get (name); if (allowedstate = null) {//New class--Remember whether it is allowed clazz = Mcontext.getclassloader (). LoadClass (pr Efix!= null?
(prefix + name): name). Assubclass (View.class);
Boolean allowed = Clazz!= null && mfilter.onloadclass (clazz);
Mfiltermap.put (name, allowed); if (!allowed) {failnotallowed (name, prefix, attrs);}}
else if (allowedstate.equals (Boolean.false)) {failnotallowed (name, prefix, attrs);}
} object[] args = Mconstructorargs;
ARGS[1] = attrs;
Return constructor.newinstance (args); ......
}

As you can see from the source, before you create an instance, you get the cache from a static map.

constructor<? Extends view> constructor = sconstructormap.get (name);

The constructor object is cached to create an instance where the Sconstructormap is static and the instance created through constructor is created using the same classloader as the constructor object. In other words, in the same process, the same custom view object is not loaded with different classloader, and if you want to solve this problem, don't let the system use the CreateView () interface to create VIEW, The practice is to customize factory or Factory2 from row creation view.

Keep looking down, and if it's not in the cache, create the view's class object Clazz and cache it into Sconstructormap.

if (constructor = null) {
//Class not found in the cache, if it's real, and try to add it
clazz = mcontext.g Etclassloader (). LoadClass (
prefix!= null? (prefix + name): name). Assubclass (View.class);
if (mfilter!= null && clazz!= null) {
Boolean allowed = Mfilter.onloadclass (clazz);
if (!allowed) {
failnotallowed (name, prefix, attrs);
}
}
constructor = Clazz.getconstructor (mconstructorsignature);
Sconstructormap.put (name, constructor);

Then it's newinstance, so this view becomes a Java object from XML, and we go back to the inflate function to see what this view does after it returns,

 ...//temp is the root view, that's found in the XML view temp; if (tag_1995.equals (name)) {temp = new Blinklayout (Mcontext, attrs);}
else {temp = Createviewfromtag (root, name, attrs);}
Viewgroup.layoutparams params = null; if (root!= null) {//Create layout params that match root, if supplied params = Root.generatelayoutparams (attrs); if (!a Ttachtoroot) {//Set the layout params for temp if we are not//attaching.
(If We are, we use AddView, below) temp.setlayoutparams (params);
}//Inflate all children under temp rinflate (parser, temp, attrs, true); We are supposed to attach "all" we found (int temp)//to root.
do so now. if (root!= null && attachtoroot) {Root.addview (temp, params);}//Decide whether to return the root this was PA
Ssed in or the//top view found in XML. 
if (root = null | |!attachtoroot) {result = temp; ... return result; 

When

Returns from Createviewfromtag, a rinflate () is invoked, where the parent argument is the view you just created, and you should be able to guess what's inside,

void Rinflate (Xmlpullparser parser, View parent, Final AttributeSet attrs, Boolean finishinflate) throws Xmlpullparserexc Eption, IOException {final int depth = parser.getdepth (); int type while ((type = Parser.next ())!= xmlpullparser.end_t
AG | | Parser.getdepth () > Depth) && type!= xmlpullparser.end_document) {if (type!= xmlpullparser.start_tag) {cont
Inue;
Final String name = Parser.getname (); if (tag_request_focus.equals (name)) {Parserequestfocus (parser, parent);} else if (tag_include.equals (name)) {if (parse R.getdepth () = = 0) {throw new Inflateexception ("<include/> cannot be the root element");} parseinclude (Parser, PA
Rent, attrs); else if (tag_merge.equals (name)) {throw new Inflateexception ("<merge/> must be the root element");} else if (TA 
G_1995.equals (name) {Final view view = new Blinklayout (Mcontext, attrs); final ViewGroup ViewGroup = (viewgroup) parent;
Final Viewgroup.layoutparams params = Viewgroup.generatelayoutparams (attrs); RInFlate (parser, view, attrs, true); 
Viewgroup.addview (view, params); else {final View view = Createviewfromtag (parent, name, Attrs); final ViewGroup ViewGroup = (viewgroup) parent; final V
Iewgroup.layoutparams params = Viewgroup.generatelayoutparams (attrs);
Rinflate (parser, view, attrs, true);
Viewgroup.addview (view, params);
} if (finishinflate) parent.onfinishinflate (); }

Yes, it's recursive. Use Createviewfromtag () to create a child view and add it to parent view through Viewgroup.addview.

After that, all the view on the view tree is created. The inflate () parameters (root and Attachtoroot) are then judged to add the newly created view to root view.

if (root!= null && attachtoroot) {
Root.addview (temp, params);
}

Then, inflate () returns the view.

The above content is small series to introduce Android from XML load to view object process parsing, hope to help everyone!

Related Article

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.