1. In the loading and drawing process of the view:Article link
We know that the view defined in the layout is loaded and parsed into the corresponding View object in Java through LayoutInflate. So what is the specific analysis process?
Let’s look at the onCreate method first, if our Activity is inherited from AppCompactActivity. android is the object setContentView returned by getDelegate. This mDelegate is an instance of AppCompatDelegateImpl.
@Override protected void onCreate(Bundle savedInstanceState) { (savedInstanceState); setContentView(.activity_main); } //getDelegate returns an instance of AppCompatDelegateImpl public void setContentView(@LayoutRes int layoutResID) { ().setContentView(layoutResID); } public AppCompatDelegate getDelegate() { if (mDelegate == null) { mDelegate = (this, this); } return mDelegate; } public static AppCompatDelegate create(@NonNull Activity activity, @Nullable AppCompatCallback callback) { return new AppCompatDelegateImpl(activity, callback); }
In AppDelegateImpl
public void setContentView(int resId) { (); //contentParent is the view with the system layout file id of content. ViewGroup contentParent = (ViewGroup)()); (); ().inflate(resId, contentParent); (); }
resource is the passed layout resource id. The system parses xml through XmlPullParser. Root is the contentView obtained above.
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) { final Resources res = getContext().getResources(); final XmlResourceParser parser = (resource); try { return inflate(parser, root, attachToRoot); } finally { (); } }
name is the name of the control defined in the layout file, LinearLayout, TextView, etc., including custom controls
attrs defines all attributes under the control, including width, height, color background, etc.
First get the root view in the layout file through createViewFromTag.
Then traverse the child View through rInflateChildren.
Finally (temp, params); add the root view of the layout file to the contentView and become a child View of it.
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) { final AttributeSet attrs = (parser); final String name = (); //The root view found in final View temp = createViewFromTag(root, name, inflaterContext, attrs); // Create layout params that match root, if supplied params = (attrs); // Inflate all children under temp against its context. //Transfer the subviews defined in the layout file and convert the view defined in the xml into the corresponding java object. rInflateChildren(parser, temp, attrs, true); if (root != null && attachToRoot) { //Add the root view defined in layout to the contentView (temp, params); } }
createViewFromTag method, create View object through name and attrs.
Then call rInflateChildren to load the child View, and convert the entire layout tree into a Java View object through loop traversal.
final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException { rInflate(parser, parent, (), attrs, finishInflate); } //Start traversal of subview void rInflate(XmlPullParser parser, View parent, Context context, AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException { while (((type = ()) != XmlPullParser.END_TAG || () > depth) && type != XmlPullParser.END_DOCUMENT) { ....... final View view = createViewFromTag(parent, name, context, attrs); final ViewGroup viewGroup = (ViewGroup) parent; final params = (attrs); rInflateChildren(parser, view, attrs, true); (view, params); } }
createViewFromTag is a key method to create View objects.
There are two ways, one is to inherit from AppCompactActivity and create a view through the factory's onCreateView.
Another type is to inherit from Activity, without setting the factory, or if the view is created through the factory fails, the onCreateView method is called for creation.
//Reflect the tags defined in the xml into the corresponding java object. View createViewFromTag(View parent, String name, Context context, AttributeSet attrs, boolean ignoreThemeAttr) { // When the Activity inherits from AppCompactActivity, it will be called when AppCompactActivity, onCreate // () Set the factory, and then call the factory method to create a view View view; if (mFactory2 != null) { view = (parent, name, context, attrs); } else if (mFactory != null) { view = (name, context, attrs); } else { view = null; } if (view == null && mPrivateFactory != null) { view = (parent, name, context, attrs); } //When the Activity inherits from Activity and the factory is not set, the following creation process is performed // Or the view is not loaded into the above method, and the following method will also be called to create the view object. if (view == null) { final Object lastContext = mConstructorArgs[0]; mConstructorArgs[0] = context; try { if (-1 == ('.')) { view = onCreateView(parent, name, attrs); } else { view = createView(name, null, attrs); } } finally { mConstructorArgs[0] = lastContext; } } return view; }
Let’s look at the first method: calling the factory’s onCreateView method is an object created by calling the name and attrs, which is directly called the View’s constructor. All the created view objects are built into the system.
final View createView(View parent, final String name, @NonNull Context context, @NonNull AttributeSet attrs, boolean inheritContext.....){ View view = null; // We need to 'inject' our tint aware Views in place of the standard versions switch (name) { case "TextView": view = createTextView(context, attrs); verifyNotNull(view, name); break; case "ImageView": view = createImageView(context, attrs); verifyNotNull(view, name); break; case "Button": view = createButton(context, attrs); verifyNotNull(view, name); break; case "EditText": view = createEditText(context, attrs); verifyNotNull(view, name); break; ............. return view; }
Let’s look at the second method: create through reflection. Through reflection, you can create a custom view object.
public final View createView(@NonNull Context viewContext, @NonNull String name, @Nullable String prefix, @Nullable AttributeSet attrs){ Class<? extends View> clazz = null; clazz = (prefix != null ? (prefix + name) : name, false, ()).asSubclass(); constructor = (mConstructorSignature); (true); //Save the resulting constructor in the map (name, constructor); final View view = (args); return view; }
Through the above two methods, the entire layout Java object conversion can be completed.
Then you can call the view drawing method to execute the view drawing process. onlayout, onMeasure, ondraw.
The framework for skinning of apps can be implemented by setting a custom factory. I have the opportunity to write an article to discuss this.
This is the article about the super detailed analysis of the LayoutInflater source code of Android for loading xml. For more related content on Android LayoutInflater, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!