Relativelayout and LinearLayout performance analysis in Android

Source: Internet
Author: User

Let's look at some phenomena: using Eclipse or Android studio, creating a new activity auto-generated layout file is Relativelayout, and you might think this is the IDE's default setting, but it's not, it's by android-sdk\ TOOLS\TEMPLATES\ACTIVITIES\BLANKACTIVITY\ROOT\RES\LAYOUT\ACTIVITY_SIMPLE.XML.FTL This file has been set up beforehand, that is, this is Google's choice, Rather than the IDE's choice. Why does the SDK default to the developer to create a default relativelayout layout? Of course, because relativelayout performance is better, performance first. But let's look at the default new Relativelayout's parent container, which is the top view--decorview of the current window, which is a vertical linearlayout with the title bar and the content bar below. So the question, why Google to developers default to create a new relativelayout, but they secretly used a linearlayout, in the end who performance is higher, how should developers choose?

Some basic works of view

Start with a few questions and simply learn how to write how view works in Android.

What is view?

In short, view is a visual representation of the Android system on the screen, meaning that what you see on your phone screen is view.

How is the view drawn?

The drawing process for view starts with the Viewroot performtraversals () method, followed by measure (), layout (), and draw () three processes to finally draw a view.

How does the view appear on the interface?

The views in Android are rendered through window, with the activity, dialog, or toast having a window and then managing the view through WindowManager. The communication between window and top-level View--decorview is dependent on viewroot completion.

What's the difference between view and ViewGroup?

Regardless of the simple button and TextView or the complex relativelayout and ListView, their common base class is view. So, view is an abstraction of an interface layer control that represents a control. That ViewGroup is something that can be translated into a group of controls, a set of view. ViewGroup also inherits view, which means that the view itself can be a single control or a group of controls consisting of multiple controls. According to this theory, the button is clearly a view, and relativelayout is not only a view can also be a viewgroup, and viewgroup inside is can have sub-view, this sub-view is also possible viewgroup, And so on

Relativelayout and LinearLayout Performance PK

Based on the above principles and the background, the performance problems we are going to discuss are simple and straightforward: when Relativelayout and LinearLayout respectively as ViewGroup, the same layout is plotted on the screen when it is faster. The above has simply described the drawing of the view, starting from the Viewroot Performtraversals () method to call Perfrommeasure, PerformLayout, and Performdraw in turn three of the methods. These three methods complete the top-level view of the measure, layout and draw three processes, where perfrommeasure will call Measure,measure and call Onmeasure, In the Onmeasure method, all child elements are measure, at which point the measure process is passed from the parent container to the child element, so that a measure process is completed, and then the child elements repeat the measure of the parent container. The traversal of the entire view tree is done so repeatedly. In the same vein, PerformLayout and Performdraw also completed perfrommeasure similar processes respectively. Through these three processes, traversing the entire view tree, the Measure,layout,draw process is realized, and the view is drawn. So we're going to have to track down the execution time of the three major processes, Relativelayout and linearlayout.
For example, we use two-way method to implement layout test

31713556b8907738423903d70a5031aa.jpglinearlayout

Measure:0.738ms
Layout:0.176ms
Draw:7.655ms

Relativelayout

Measure:2.280ms
Layout:0.153ms
Draw:7.696ms
From this data point of view, regardless of the use of relativelayout or linearlayout,layout and draw the same process, considering the problem of error, can almost think of the two, The key is that the measure process relativelayout a lot slower than linearlayout.

What did measure do? Relativelayout's Onmeasure () method
View[] views = Msortedhorizontalchildren; int count = Views.length;for (int i =0; I < count; i++) {View child = views[i];if (child.getvisibility () = GONE) {layoutparams params = (layoutparams) child.getlayoutparams ();        Int[] Rules = Params.getrules (layoutdirection);        Applyhorizontalsizerules (params, mywidth, rules); Measurechildhorizontal (Child, params, mywidth, myheight);if (Positionchildhorizontal (child, params, mywidth, iswrapcontentwidth)) {Offsethorizontalaxis =True }}} views = Msortedverticalchildren; Count = Views.length; Final int targetsdkversion = GetContext (). Getapplicationinfo (). targetsdkversion;for (int i =0; I < count; i++) {View child = views[i];if (child.getvisibility () = GONE) {layoutparams params = (layoutparams) child.getlayoutparams (); Applyverticalsizerules (params, myheight); Measurechild (Child, params, mywidth, myheight);if (positionchildvertical (child, params, myheight, iswrapcontentheight)) {Offsetverticalaxis =True }if (iswrapcontentwidth) {if (Islayoutrtl ()) {if (Targetsdkversion < build.version_codes. KITKAT) {width =Math.max (width, mywidth-params.mleft); }else {width =Math.max (width, mywidth-params.mleft-params.leftmargin); } }else {if (Targetsdkversion < build.version_codes. KITKAT) {width =Math.max (width, params.mright); }else {width =Math.max (width, params.mright + params.rightmargin); } } }if (iswrapcontentheight) {if (Targetsdkversion < Build.version_codes. KITKAT) {height = math.max (height, params.mbottom);} else {height = math.max (height, params.mbottom + Params.bottommargin); }} if (child! = Ignore | | verticalgravity) {left = math.min (left , Params.mleft-params.leftmargin); top = math.min (top, params.mtop-params.topmargin);} if (child! = Ignore | | horizontalgravity) {right = math.max ( Right, params.mright + params.rightmargin); Bottom = math.max (bottom, Params.mbottom + Params.bottommargin);}} }

According to the source we found that Relativelayout will do a pair of views do two times measure. What is this for? First, the relativelayout of the neutron view is based on each other's dependencies, and this dependency may not be the same as the order of the view in the layout, and in determining the location of each sub-view, you need to sort all the sub-view first. Also because Relativelayout allows a A, a, B 2 sub-view, a cross-over on a, vertical a depends on B. So we need to do a sort of horizontal longitudinal measurement separately.

LinearLayout's Onmeasure () method
  @Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mOrientation == VERTICAL) { measureVertical(widthMeasureSpec, heightMeasureSpec); } else { measureHorizontal(widthMeasureSpec, heightMeasureSpec); } }

Compared with relativelayout, LinearLayout's measure is much simpler and clearer, first judging the linear rule and then performing the measurement in the corresponding direction. Take a look at it.

for (int i =0; I < count; ++i) {Final View child = Getvirtualchildat (i);if (Child = =NULL) {mtotallength + = Measurenullchild (i);Continue }if (child.getvisibility () = = View.gone) {i + = Getchildrenskipcount (child, I);Continue }if (Hasdividerbeforechildat (i)) {mtotallength + = Mdividerheight;} Linearlayout.layoutparams LP = (linearlayout.layoutparams) child.getlayoutparams (); Totalweight + = Lp.weight;if (Heightmode = = measurespec.exactly && Lp.height = =0 && lp.weight >0) {Optimization:don ' t bother measuring children who is going to useLeftover space. These views would get measured again down below ifThere is any leftover space.Finalint totallength = Mtotallength; Mtotallength = Math.max (totallength, totallength + lp.topmargin + lp.bottommargin); }else {int oldheight = Integer.min_value;if (Lp.height = =0 && lp.weight >0) {Heightmode is either UNSPECIFIED or at_most, and thisChild wanted to stretch to fill available space.Translate that to wrap_content so it does not end upWith a height of 0 oldheight =0; Lp.height = layoutparams.wrap_content; }Determine how big the would like to IS. If this orPrevious children has given a weight, then we allow it to//use all available space (and we'll shrink things later //if NE eded). Measurechildbeforelayout (Child, I, Widthmeasurespec, 0, heightmeasurespec, totalWeight = = Span class= "Hljs-number" >0? Mtotallength: 0); if (oldheight! = integer.min_value) {lp.height = OldHeight;} final int childheight = Child.getmeasuredheight (); final int totallength = mtotallength; mtotallength = Math.max (TotalLength, Totallength + childheight + lp.topmargin + lp.bottommargin + getnextlocationoffset (child)); if (uselargestchild) {largestchildheight = Math.max (Childheight, largestChildHeight);}} 

The parent view uses the variable mtotallength to hold the height of the child that has been measure during the measure operation of the sub-view, which is initially 0. In the For loop, call Measurechildbeforelayout () to measure each child, which is actually just a call to Measurechildwithmargins (), and when the method is called, two parameters are used. One is Heightmeasurespec, which is the measurespec of LinearLayout itself, and the other is Mtotallength, which represents the height that the linearlayout has been occupied by its child views. Each time the for loop has been measured for the child, call Child.getmeasuredheight () to get the final height of the sub-view and add the height to the mtotallength. In This step, the child view of Lp.weight>0 is temporarily bypassed, that is, the sub-views are not measured for the time being, because the remaining height of the parent view is assigned evenly to the corresponding sub-view according to the size of the weight value. the source uses a local variable totalweight the weight value of all the child views. When dealing with lp.weight>0, it is important to note that if the variable heightmode is exactly, when the other child views occupy the height of the parent view, the Weight>0 child view may not be assigned to the layout space and thus not be displayed. The weight>0 view takes precedence over the layout height only if Heightmode is at_most or unspecified. Finally, we conclude that if you do not use the weight property, LinearLayout will perform a measure process in the current direction, and if you use the Weight property, LinearLayout will avoid setting the weight attribute of the view to do the first measure, and then set the weight properties of the view to do a second measure. This shows that the weight property has an impact on performance, and itself has a big pit, please pay attention to avoidance.

Summary

From the source we seem to be able to see, our previous test results relativelayout than linearlayout fast root cause is relativelayout need to its sub-view two measure process. LinearLayout, however, requires only one measure process, so it is obviously faster than relativelayout, but if there is a weight attribute in LinearLayout, it also needs to be measure two times, but even so, Should still be a little better than the relativelayout situation.

Relativelayout another performance issue

Is this the end of the comparison? Apparently not! Let's see what the measure () method of view is doing.

public final void measure  (int Widthmeasurespec, int Heightmeasurespec) {if ((mprivateflags & pflag_force_layout) = = Pflag_force_layout | | Widthmeasurespec! = Moldwidthmeasurespec | | Heightmeasurespec! = Moldheightmeasurespec) {...} moldwidthmeasurespec = Widthmeasurespec; Moldheightmeasurespec = Heightmeasurespec; Mmeasurecache.put (Key, ((long) mmeasuredwidth) << 32 | (long) Mmeasuredheight & 0XFFFFFFFFL); //suppress sign extension}           

The measure method of the view makes an optimization of the drawing process, if we or our child view does not require forced refresh, and the parent view to the child view of the incoming value does not change (that is, the location of the child view does not change), do not do unnecessary measure. But the above has said relativelayout to do two times measure, and in the horizontal measurement, longitudinal measurement results have not been completed, had to temporarily use Myheight into the sub-view system, If the height of the child view is not equal to (set the margin) Myheight, then the optimization of the above code in measure will not work, this process will further affect the drawing performance of Relativelayout. LinearLayout, however, has no such concerns. Solve this problem is also very good to do, if possible, try to use padding instead of margin.

Conclusion

1.RelativeLayout will make the child view call 2 times onmeasure,linearlayout when there is weight, it will also call View2 times onmeasure
2.RelativeLayout Sub-view if the height and relativelayout are different, it will raise the efficiency problem, when the sub-view is very complex, this problem is more serious. If possible, use padding instead of margin.
3. Without affecting the depth of the hierarchy, use LinearLayout and framelayout instead of relativelayout.
Finally think about the article at the beginning of the contradiction of the question, why Google gave developers a default new Relativelayout, and they are in Decorview used a linearlayout. Because the level depth of the decorview is known and fixed, above a title bar, below a content bar. Using relativelayout does not degrade the depth of the hierarchy, so it is most efficient to use linearlayout on the root node at this time. The reason for developers to create a new relativelayout by default is that developers can use as few view levels as possible to express layouts for optimal performance, because complex view nesting has a greater impact on performance.



Relativelayout and LinearLayout performance analysis in Android

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.