The introduction

  • This is the fourth installment in our Android 10 source code analysis series
  • Branches: android – 10.0.0 _r14
  • Read the full text for about 10 minutes

In this article you will learn the following, and the answers will be given at the end of the article

  • What are the functions of INVISIBLE, VISIBLE and GONE in View?
  • Why is ViewStub a view of size 0
  • What does the ViewStub do?
  • How is the ViewStub created?
  • Why is the ViewStub lazy loading?
  • When is the Layout file specified by the ViewStub loaded?
  • LayoutInflater is an abstract class how is it created?
  • Where are system services stored? How do I obtain and add system services?

0xA02 Android 10 XML files are parsed with the Layoutinflater.inflate method during the resource loading process of Apk. This article focuses on how merge and include tags are handled

  • How does the system handle the ViewStub?
  • How are Layoutinflaters created?

How does the system process merge and include

  • To use merge tags, you must have a parent layout and depend on the parent layout to load
  • Merge is not a ViewGroup, it is not a View, it is a declaration of views, waiting to be added to the root layout when the merge tag is used
  • The Merge tag must be the root element in XML
  • The opposite include cannot be the root element and needs to be placed in a ViewGroup
  • To use the include tag, you must specify a valid Layout attribute
  • It doesn’t matter if you use the include tag to parse the included layout

Why does merge tag optimize layout?

When the merge tag is encountered during parsing, the rInflate method is called, as shown in the following code

Final View view = createViewFromTag(parent, name, context, attrs); final ViewGroup viewGroup = (ViewGroup) parent; final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs); // The rInflateChildren method is called internally by the rInflateChildren method, which plodes through all the child views rInflateChildren(Parser, View, attrs, true); // Add parsed view viewgroup. addView(view, params);Copy the code

Parse all subviews under the merge tag, and add them to the root layout

1. What is a ViewStub

Information about the ViewStub, can click on the below website link to check the website https://developer.android.google.cn/reference/android… ViewStub

ViewStub inheritance structure

In brief, the main points are as follows:

  • The ViewStub control is an invisible,
  • View of size 0
  • The Layout resource specified by the ViewStub is loaded when the ViewStub control is set visible or when the inflate() method is called
  • The ViewStub is also removed from its parent control and replaced by a newly loaded Layout file

Why ViewStub is a size of 0 view frameworks/base/core/Java/android/view/ViewStub. Java

Protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(0, 0); }Copy the code

The role of ViewStub

Mainly used to delay the loading of layouts, for example: Loading an empty ListView will take up some resources if there is no data or if the network fails to load. If you wrap the ListView with a ViewStub, when there is data, The inflate() method is called to display the ListView, lazy-loading the layout

1.1 How is a ViewStub created

0xA02 Android 10 Apk resource loading of loading process, this paper introduces the view is created by calling the LayoutInflater. CreateView method according to the full path name of a class using reflection mechanism building view objects, because the ViewStub is inherited the view, So ViewStub create and View the creation of the is the same, look at the LayoutInflater. CreateView method frameworks/base/core/Java/android/View/LayoutInflater. Java

. Try {// Create View final View with constructor View = constructive.newinstance (args); If (View instanceof ViewStub) {// If it is a ViewStub, set LayoutInflater final ViewStub ViewStub = (ViewStub) view; viewStub.setLayoutInflater(cloneInContext((Context) args[0])); } return view; } finally { mConstructorArgs[0] = lastContext; }...Copy the code

View objects are built using reflection mechanisms based on the path name of the full class. If a ViewStub is encountered, set the current LayoutInflater to ViewStub, when the ViewStub control is set visible, or call inflate(). The layout is loaded by calling the Inflate method of the LayoutInflater, and the constructor of the ViewStub is then analyzed

1.2 Constructor of ViewStub

When a View object is created, its constructor is called. Take a look at the constructor of the ViewStub

public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewStub, defStyleAttr, defStyleRes); saveAttributeDataForStyleable(context, R.styleable.ViewStub, attrs, a, defStyleAttr, defStyleRes); MInflatedId = A.getResourceId (r.tyleable. ViewStub_inflatedId, NO_ID); mInflatedId = A.getResourceId (r.tyleable. ViewStub_inflatedId, NO_ID); // Parse the Android: Layout property set in the XML. MLayoutResource = A.getResourceId (r.tyleable.viewStub_layout, 0); // Parse the Android :id attribute set in XML mID = a.getResourceId(r.tyleable.viewstub_id, NO_ID); a.recycle(); // view undefined setVisibility(GONE); // The onDraw method will not be called setWillNotDraw(true); }Copy the code
  1. Get android:inflatedId, Android: Layout, and Android: ID values
  2. Call the setVisibility method to make the View invisible
  3. The setWillNotDraw method is called; the onDraw method is not called to draw the content

As mentioned above, if you want to load the Layout resource specified by the ViewStub, you need to set the ViewStub control visible or call the inflate() method. Look at the setVisibility method of the ViewStub

1.3 setVisibility method of ViewStub

SetVisibility (int visibility) method. The values of the parameter visibility are INVISIBLE, VISIBLE, and GONE

  • VISIBLE: The view is VISIBLE
  • INVISIBLE: A view that is not visible and that still occupies space in a layout
  • GONE: The view is not visible and does not take up space in the layout

Next check ViewStub method setVisibility frameworks/base/core/Java/android/view/ViewStub. Java

@Override public void setVisibility(int visibility) { if (mInflatedViewRef ! {// mInflatedViewRef is an instance of a WeakReference, and the View View = minFlatedViewRef.get () is initialized when the inflate method is called; if (view ! = null) {// Set viewview.setvisibility (visibility); } else { throw new IllegalStateException("setVisibility called on un-referenced view"); } } else { super.setVisibility(visibility); / / when the View is empty and set the View VISIBLE (VISIBLE and INVISIBLE), if call inflate method (visibility = = VISIBLE | | visibility = = cause) {inflate (); }}}Copy the code
  1. MInflatedViewRef is an instance of a WeakReference that is initialized when the Inflate method is called
  2. Get the View from the mInflatedViewRef cache and make the View visible
  3. The inflate method is called when the View is empty and the View is made VISIBLE (VISIBLE, INVISIBLE)

1.4 ViewStub. Inflate method

Call the ViewStub setVisibility method, finally will be called ViewStub. Inflate method, to check the frameworks/base/core/Java/android/view/ViewStub. Java

public View inflate() { final ViewParent viewParent = getParent(); if (viewParent ! = null && viewParent instanceof ViewGroup) { if (mLayoutResource ! = 0) { final ViewGroup parent = (ViewGroup) viewParent; View = inflateViewNoAdd(parent); view = inflateViewNoAdd(parent); ReplaceSelfWithView (view, parent); replaceSelfWithView(view, parent); MInflatedViewRef = new WeakReference<>(view); mInflatedViewRef = new WeakReference<>(view); if (mInflateListener ! = null) {/ / loading is completed, the callback method onInflate mInflateListener. OnInflate (this view); } return view; } else {// You need to set android:layout in XML, not layout, Throw new IllegalArgumentException("ViewStub must have a valid layoutResource"); }} else {// ViewStub cannot be used as the root layout, Throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent"); }}Copy the code
  1. Call the inflateViewNoAdd method to return the view at the top of the layout file specified by Android: Layout
  2. Call the replaceSelfWithView method to remove the ViewStub and add the view to the position of the removed ViewStub
  3. Add a View to the mInflatedViewRef
  4. After loading is complete, call back to the onInflate method

Note the following two points:

  • To use the ViewStub, you need to set Android: Layout in the XML, not Layout, otherwise an exception will be thrown
  • The ViewStub cannot be used as the root layout; it needs to be placed in the ViewGroup or an exception will be thrown

Let’s look at inflateViewNoAdd and replaceSelfWithView

1.5 ViewStub. InflateViewNoAdd method

Call inflateViewNoAdd method returns the android: layout the layout of the specified file at the top of the view frameworks/base/core/Java/android/view/ViewStub. Java

private View inflateViewNoAdd(ViewGroup parent) { final LayoutInflater factory; // mInflater is when a View is created. If it is a ViewStub, assign the LayoutInflater value to mInflater if (mInflater! = null) { factory = mInflater; } else {// If mInflater is empty, create LayoutInflater Factory = LayoutInflater. From (mContext); } // Parse the layout View from the specified mLayoutResource // mLayoutResource is the layout file specified in the XML setting Android: Layout final View View = factory.inflate(mLayoutResource, parent, false); // mInflatedId is inflateId if (mInflatedId! = NO_ID) {// Copy the id to view view.setid (mInflatedId); // Note: If mInflatedId is specified, the ID of the layoutView inflate is mInflatedId} return view; }Copy the code
  • MInflater is when a View is created. If it is a ViewStub, assign a LayoutInflater value to the mInflater
  • If mInflater is empty, the LayoutInflater is built using LayoutInflater. From (mContext)
  • The inflate method of the LayoutInflater is called to resolve the layout view
  • Set mInflatedId to View

1.6 ViewStub. ReplaceSelfWithView method

Call replaceSelfWithView method, removing ViewStub, add the position of the view to be removed the ViewStub frameworks/base/core/Java/android/view/ViewStub. Java

private void replaceSelfWithView(View view, Final int index = parent.indexofChild (this); / / remove ViewStub / / note: call removeViewInLayout method, called the findViewById () is to find the ViewStub object parent. RemoveViewInLayout (this); final ViewGroup.LayoutParams layoutParams = getLayoutParams(); // Add the top-level View from the Android: Layout file specified in the XML to the position of the removed ViewStub if (layoutParams! = null) { parent.addView(view, index, layoutParams); } else { parent.addView(view, index); }}Copy the code
  1. Gets the ViewStub position in the view, and then removes the ViewStub
  2. Add the top View from the Android: Layout file to the position of the removed ViewStub

1.7 Precautions of ViewStub

  • To use the ViewStub, you need to set Android: Layout in the XML, not Layout, otherwise an exception will be thrown
throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
Copy the code
  • The ViewStub cannot be used as the root layout; it needs to be placed in the ViewGroup or an exception will be thrown
throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
Copy the code
  • Once the setVisibility(view.visible) or inflate() method is called, the ViewStub object will be removed from the public View (findViewById() does not find the ViewStub object).
Final int index = parent.indexofChild (this); / / remove ViewStub / / note: call removeViewInLayout method, called the findViewById () is to find the ViewStub object parent. RemoveViewInLayout (this);Copy the code
  • If mInflatedId is specified, the ID of the layoutView inflate is the mInflatedId
// mInflatedId is inflateId if (mInflatedId! = NO_ID) {// Copy the id to view view.setid (mInflatedId); // Note: If mInflatedId is specified, the ID of the layoutView inflate is mInflatedId}Copy the code
  • The layoutParams of the synchronized layoutView are the same as the layoutParams of the ViewStub.
final ViewGroup.LayoutParams layoutParams = getLayoutParams(); // Add the top View (root View) of the Android: Layout file specified in the XML to the position of the removed ViewStub if (layoutParams! = null) { parent.addView(view, index, layoutParams); } else { parent.addView(view, index); }Copy the code

How are LayoutInflaters created

2 about the LayoutInflater

0xA02 Android 10 Layoutinflaters are created by calling layoutinflaters when an Activity starts. Layoutinflaters are created by calling layoutinflaters when an Activity starts

public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
    return new AllVh(LayoutInflater
            .from(viewGroup.getContext())
            .inflate(R.layout.list_item, viewGroup, false));
}
Copy the code

What do the three arguments to the inflate method of a LayoutInflater stand for?

  • Resource: Id of the XML layout file to parse
  • Root: indicates the root layout
  • AttachToRoot: Whether to add to the parent layout root

Resource = resource Id, root = resource Id, attachToRoot = resource Id

  • When attachToRoot == true and root! = null, the newly parsed View is added to root, and root is returned as the result
  • When attachToRoot == false and root! = null, the newly parsed View is returned as a result, and root generates and sets LayoutParams for the newly parsed View
  • When attachToRoot == false and root == NULL, the newly parsed View is returned directly as the result

2.1 How are Layoutinflaters created

PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater The inheritance structure is as follows:

Layoutinfler. from(CTX) is the Context that’s passed in, Invoking getSystemService () to obtain the corresponding system services, take a look at this method frameworks/base/core/Java/android/view/LayoutInflater. Java

Public static LayoutInflater from(Context Context) {// Get system service LAYOUT_INFLATER_SERVICE, And assign to LayoutInflater // Context is an abstract class, So the actual implementation class is ContextImpl LayoutInflater LayoutInflater = LayoutInflater context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (LayoutInflater == null) { throw new AssertionError("LayoutInflater not found."); } return LayoutInflater; }Copy the code

And the Context itself is an abstract class, it is real object instantiated ContextImpl frameworks/base/core/Java/android/app/ContextImpl. Java

Public Object getSystemService(String name) {public Object getSystemService(String name) {// SystemServiceRegistry Through a service name to find the corresponding service return SystemServiceRegistry. GetSystemService (this, name); }Copy the code

2.2 SystemServiceRegistry

SystemServiceRegistry manages all system services by calling getSystemService, Through a service name to find the corresponding service frameworks/base/core/Java/android/app/SystemServiceRegistry. Java

public static Object getSystemService(ContextImpl ctx, String name) {// SYSTEM_SERVICE_FETCHERS is a map set // Fetch system service ServiceFetcher<? > fetcher = SYSTEM_SERVICE_FETCHERS.get(name); return fetcher ! = null ? fetcher.getService(ctx) : null; }Copy the code
  • ServiceFetcher defines the getService method for the static internal interface of the SystemServiceRegistry class
  • The implementation class CachedServiceFetcher implements the getService method
  • All system services are stored in a map collection SYSTEM_SERVICE_FETCHERS, and the get method is called to get the corresponding service

If there are getSystemService method to get the service, then the corresponding method of adding services also have frameworks/base/core/Java/android/app/SystemServiceRegistry. Java

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);
}
Copy the code

Add data to the map collection by calling the SYSTEM_SERVICE_NAMES put method, so when registerService is called, search the SystemServiceRegistry class for the registerService method, Now that you know it’s added in a static code block at class load time, let’s take a look

Static {// Initialize all system services... RegisterService (context.layout_inflater_service, LayoutInflater. Class, registerService(context.layout_inflater_service, LayoutInflater. new CachedServiceFetcher<LayoutInflater>() { @Override public LayoutInflater createService(ContextImpl ctx) { return new  PhoneLayoutInflater(ctx.getOuterContext()); }}); . // Omitted many system services}Copy the code

Finally, a PhoneLayoutInflater is created and returned, and the LayoutInflater creation process is finished

conclusion

What are the functions of INVISIBLE, VISIBLE and GONE in View?

If you want to hide or display the View, you can use setVisibility(int visibility) to achieve this. The three values of the parameter visibility are INVISIBLE, VISIBLE, and GONE

  • VISIBLE: The view is VISIBLE
  • INVISIBLE: A view that is not visible and that still occupies space in a layout
  • GONE: The view is not visible and does not take up space in the layout

Why is ViewStub a view of size 0? frameworks/base/core/java/android/view/ViewStub.java

Protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(0, 0); }Copy the code

What does the ViewStub do?

The main purpose of the ViewStub is to delay loading the layout

How is the ViewStub created?

Since a ViewStub inherits a View, the creation of a ViewStub is the same as the creation of a View, By calling the LayoutInflater. CreateView method according to the full path name of a class using reflection mechanism to build the View object frameworks/base/core/Java/android/View/LayoutInflater. Java

. Try {// Create View final View with constructor View = constructive.newinstance (args); If (View instanceof ViewStub) {// If it is a ViewStub, set LayoutInflater final ViewStub ViewStub = (ViewStub) view; viewStub.setLayoutInflater(cloneInContext((Context) args[0])); } return view; } finally { mConstructorArgs[0] = lastContext; }...Copy the code

Why is the ViewStub lazy loading?

Since you encounter a ViewStub during layout file parsing, you just build the ViewStub object and initialize its properties without actually parsing the view, so you can do lazy initialization

When is the Layout file specified by the ViewStub loaded?

The Layout resource specified by the ViewStub is loaded when the ViewStub control is set visible or when the inflate() method is called

LayoutInflater is an abstract class how is it created?

PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater: PhoneLayoutInflater The inheritance structure is as follows:

Layoutinfler. from(CTX) calls getSystemService() to obtain the corresponding system service based on the passed Context object

Where are system services stored? How do I obtain and add system services?

SystemServiceRegistry manages all system services. All system services are stored in a map called SYSTEM_SERVICE_FETCHERS. Call getSystemService to get system services. Call the registerService method to add a system service

conclusion

Dedicated to share a series of Android system source code, reverse analysis, algorithm, translation, Jetpack source code related articles, is trying to write a better article, if this article is helpful to you to give a star, what is not written in the article clearly, or have better advice, welcome to leave a message, welcome to learn together, Moving forward together on the technological road.

Plan to establish a most complete and latest AndroidX Jetpack related components of the actual combat project and related components of the principle of analysis article, is gradually increasing Jetpack new members, the warehouse continues to update, you can go to check: Androidx-jetpack-practice, if this warehouse is helpful to you, please give me a thumbs up and I will finish more project practices for new members of Jetpack one after another.

algorithm

Since LeetCode has a large question bank, hundreds of questions can be selected for each category. Due to the limited energy of each person, it is impossible to brush all the questions. Therefore, I sorted the questions according to the classic types and the difficulty of the questions.

  • Data structures: arrays, stacks, queues, strings, linked lists, trees…
  • Algorithms: Search algorithm, search algorithm, bit operation, sorting, mathematics,…

Each problem will be implemented in Java and Kotlin, and each problem has its own solution ideas, time complexity and space complexity. If you like algorithms and LeetCode like me, you can pay attention to my LeetCode problem solution on GitHub: Leetcode-Solutions-with-Java-And-Kotlin, come to learn together And look forward to growing with you.

Android 10 source code series

I’m writing a series of Android 10 source code analysis articles. Knowing the system source code is not only helpful in analyzing problems, but also very helpful in the interview process. If you like to study Android source code as MUCH as I do, You can follow my Android10-source-Analysis on GitHub, and all articles will be synchronized to this repository.

  • How is APK generated
  • APK installation process
  • 0xA03 Android 10 source code analysis: APK loading process of resource loading
  • Android 10 source code: APK
  • Dialog loading and drawing process and use in Kotlin, DataBinding
  • More……

Tool series

  • Shortcuts to AndroidStudio that few people know
  • Shortcuts to AndroidStudio that few people know
  • All you need to know about ADB commands
  • How to get video screenshots efficiently
  • 10 minutes introduction to Shell scripting
  • How to package Kotlin + Android Databinding in your project

The reverse series

  • Dynamically debug APP based on Smali file Android Studio
  • The Android Device Monitor tool cannot be found in Android Studio 3.2