Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the knowledge points of LayoutInflater in Android

2025-03-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly introduces the relevant knowledge of "what are the knowledge points of LayoutInflater in Android". The editor shows you the operation process through actual cases, the method of operation is simple and fast, and it is practical. I hope that this article "what are the knowledge points of LayoutInflater in Android" can help you solve the problem.

First of all, summarize what LayoutInflater is used for.

As we all know, when developing Android applications, layouts are basically written through xml files. Of course, you can also write the layout by hand in the code, but everyone who has written it knows that it will be very troublesome to write the layout.

So how does a layout file written through xml be converted into a View object in Android and displayed in the application? That's what LayoutInflater is for.

To put it simply, LayoutInflater's job is to convert layouts written in xml files into View objects in Android, and this is the only way in Android to convert xml layouts to View.

Some friends may say, "No, I don't usually use LayoutInflater,xml layouts to convert View. Can't you just call the setContentView () method in Activity?"

This is because Android SDK has done some good encapsulation for us at the upper level, which makes the development work easier. If you open the source code of the setContentView () method to learn about it, you will find that its underlying LayoutInflater is also used:

@ Overridepublic void setContentView (int resId) {ensureSubDecor (); ViewGroup contentParent = mSubDecor.findViewById (android.R.id.content); contentParent.removeAllViews (); LayoutInflater.from (mContext) .propagate (resId, contentParent); mAppCompatWindowCallback.getWrapped () .onContentChanged ();}

So how does LayoutInflater convert an xml layout into a View object?

This is a very complex process, of course, but if you summarize it briefly, the most important thing is two steps:

Parse the contents of the xml file through a parser.

Use reflection to create parsed elements as View objects.

Here I do not want to follow the source code step by step in the article, so the article may look tired and boring, so I will only post some code that I think is more critical.

Code snippet that parses the contents of the xml file:

Public View inflate (@ LayoutRes int resource, @ Nullable ViewGroup root, boolean attachToRoot) {... XmlResourceParser parser = res.getLayout (resource); try {return inflate (parser, root, attachToRoot);} finally {parser.close ();}}

As you can see, a XmlResourceParser object is obtained here to parse the xml file. As the specific parsing rules are too complex, we will not follow them.

Create a code snippet of a View object using reflection:

Public final View createView (@ NonNull Context viewContext, @ NonNull String name, @ Nullable String prefix, @ Nullable AttributeSet attrs) throws ClassNotFoundException, InflateException {... If (constructor = = null) {/ / Class not found in the cache, see if it's real, and try to add it clazz = Class.forName (prefix! = null? (prefix + name): name, false, mContext.getClassLoader () .asSubclass (View.class); constructor = clazz.getConstructor (mConstructorSignature); constructor.setAccessible (true); sConstructorMap.put (name, constructor);}. Try {final View view = constructor.newInstance (args); if (view instanceof ViewStub) {/ / Use the same context when inflating ViewStub later. Final ViewStub viewStub = (ViewStub) view; viewStub.setLayoutInflater (cloneInContext ((Context) args [0]));} return view;}...}

Seeing here, we have a basic understanding of how LayoutInflater works.

But as mentioned earlier, the purpose of this article is not to take you to read the source code, but to get some new understanding of LayoutInflater from the usage level.

Then the most common use of LayoutInflater is as follows:

View view = LayoutInflater.from (context) .propagate (resourceId, parent, false)

This code means that you first call the from () method of LayoutInflater to get an instance of LayoutInflater, and then call its inflate () method to parse and load a layout, which is converted to a View object and returned.

However, I think this code is very unfriendly for beginners, even for many veterans.

Let's take a look at the parameter definition of the inflate () method:

Public View inflate (int resource, @ Nullable ViewGroup root, boolean attachToRoot) {...}

The inflate () method takes three parameters, and the first parameter, resource, is easy to understand, which is that we want to parse the resource id of the loaded xml file. What does the second parameter root and the third parameter attachToRoot mean? Perhaps even many programmers who have been developing Android for many years may not be able to explain it clearly.

And this code is bound to be used when we use RecyclerView or Fragment. When I wrote the first line of code, I always felt that this piece of content was not good because I had to talk about the use of RecyclerView in a very early chapter, but I found it difficult to explain the relevant content of LayoutInflater to beginners. You can only memorize it by rote and remember that this part of the code must be written in this way for the time being.

Today, I hope to be able to make LayoutInflater really clear.

We know that the layout structure of Android is a tree-like structure. Each layout can contain several sub-layouts, and each sub-layout can continue to contain sub-layouts, thus building any style of View to present to the user.

Therefore, we can roughly understand that every layout has to have a parent layout.

This is also the function of the second parameter root of the inflate () method, which is to specify a parent layout for the xml layout that is currently being parsed and loaded.

So can a layout without a parent layout? Of course, it is also possible, which is why the root parameter is marked @ Nullable.

But if we inflate a layout without a parent layout, how do we show it? Of course, there is no way to show it, so you can only use addView to add it to an existing layout later. Or maybe your inflate layout is a top-level layout, so it doesn't need to have a parent layout. But these scenarios are rare, so in most cases, we specify the parent layout when we use the inflate () method of LayoutInflater.

In addition, if you do not specify a parent layout for the layout that comes out of inflate, another problem will arise, which we will explain with an example.

Here we define a button_layout.xml layout file with the following code:

This layout file is very simple, with only one button in it.

Next we use LayoutInflater to load the layout file and add it to an existing layout:

Public class MainActivity extends Activity {@ Override protected void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); LinearLayout mainLayout = (LinearLayout) findViewById (R.id.main_layout); View buttonLayout = LayoutInflater.from (this) .propagate (R.layout.button_layout, null); mainLayout.addView (buttonLayout) }}

As you can see, instead of specifying a parent layout for button_layout, we pass in a null. When the second parameter is passed in null, the third parameter is meaningless, so you don't have to specify it.

But as mentioned earlier, a layout cannot be displayed without a parent layout, so we use the addView () method to add it to an existing layout.

The code is that simple, and now we can run the program, as shown in the following figure:

There seems to be no problem, and the button has been displayed normally, indicating that the button_layout.xml layout has indeed been successfully loaded and added to the existing layout.

But if you try to resize the button, you will find that no matter how you adjust it, the size of the button will not change:

Here we specify the width and height of the button as 300dp and the height as 100dp, and the interface for rerunning the program remains unchanged.

Why did this happen?

In fact, no matter how much you change the layout_width and layout_height values of Button, it will not have any effect, because these two values are now completely useless. We often use layout_width and layout_height to set the size of View, and it works all the time, as if these two properties are actually used to set the size of View.

In fact, they are not, they are actually used to set the size of View in the layout, that is, the View must first exist in a layout. That's why these two properties are called layout_width and layout_height, not width and height.

Because we didn't specify a parent layout for the layout when using LayoutInflater to load button _ layout.xml, both the layout_width and layout_height properties have no effect here. To be more precise, all attributes that start with layout_ will have no effect.

Now let's make the following changes to the code:

Public class MainActivity extends Activity {@ Override protected void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); LinearLayout mainLayout = (LinearLayout) findViewById (R.id.main_layout); View buttonLayout = LayoutInflater.from (this) .propagate (R.layout.button_layout, mainLayout, false); mainLayout.addView (buttonLayout) }}

As you can see, the second parameter of the inflate () method is specified as mainLayout. That is, we specify a parent layout for the button_layout.xml layout. In this way, the layout_width and layout_height properties can take effect.

Rerun the program, as shown in the following figure:

So far, we have explained the role of root, the second parameter of the inflate () method, very clearly. So another question is, what does the third parameter, attachToRoot, mean?

Noticing the above code, we specify the second parameter as mainLayout and the third parameter as false. If you try to specify the third parameter as true, and then rerun the code, the program will crash directly. The crash message is as follows:

The crash message says that we are adding a child View, but the child View already has a parent layout, which needs to be added after the parent layout calls removeView () to remove the child View.

Why does such an error occur after modifying the third parameter? Let's analyze it now.

First take a look at what the name of the third parameter is, attachToRoot. Literally, it's asking if we want to add it to root. So what is root? If you look at the definition of the inflate () method again, you will find that the second parameter is not root.

Public View inflate (int resource, @ Nullable ViewGroup root, boolean attachToRoot) {...}

In other words, attachToRoot is asking if we want to add the currently loaded xml layout to the parent layout passed in by the second parameter. If you pass in true, it means it will be added, and if you pass in false, it will not be added.

So in the code just now, we first passed false in the third parameter of the inflate () method, so the button_layout.xml layout will not be added to the mainLayout, and then we can manually call the addView () method to add it to the mainLayout.

If you change the third parameter to true, it means that the button_layout.xml layout has been automatically added to the mainLayout. Call the addView () method again and find that button_layout.xml already has a parent layout, and the above exception will be thrown naturally.

After this explanation, do you understand the role of each parameter in the inflate () method?

In fact, with this understanding, we can go back and take a look at the code written in the past. For example, everyone must have used Fragment. When loading a layout in Fragment, we usually write:

Public class MyFragment extends Fragment {@ Nullable @ Override public View onCreateView (@ NonNull LayoutInflater inflater, @ Nullable ViewGroup container, @ Nullable Bundle savedInstanceState) {return inflater.inflate (R.layout.fragment_layout, container, false);}}

Have you ever wondered why the last parameter of the inflate () method has to be passed in false?

So now you can think about it. If you look at the relevant source code of Fragment, you will find that it adds the View we returned in the onCreateView () method to a Container:

Void addViewToContainer () {/ / Ensure that our new Fragment is placed in the right index / / based on its relative position to Fragments already in the / / same container int index = mFragmentStore.findFragmentIndexInContainer (mFragment); mFragment.mContainer.addView (mFragment.mView, index);}

This situation is very similar to our example just now, that is, the subsequent Fragment will have an addView operation of its own, and if we pass the third parameter of the inflate () method into true, then the layout from inflate will be directly added to the parent layout. When you addView again later, you will find that it already has a parent layout, thus throwing the same crash message as above.

This is the end of the content about "what are the knowledge points of LayoutInflater in Android". Thank you for your reading. If you want to know more about the industry, you can follow the industry information channel. The editor will update different knowledge points for you every day.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report