Android layout Performance Optimization-ViewStub latency loading technology from the source code perspective
This requirement is inevitable in projects. When running a program, you need to dynamically decide which View or layout to display based on the conditions, the most common idea is to write the views to be dynamically displayed in the layout, and then set their visibility to View. GONE, and finally control the View in the code. VISIABLE dynamically changes its visibility. This method has the advantages of simple logic and flexible control. However, its disadvantage is that it consumes resources, although the initial View is visible. GONE is still Inflate in the Inflate layout. In other words, an object will be created, instantiated, and set attributes. That is to say, it will consume memory and other resources.
We recommend that you use android. view. ViewStub. ViewStub is a lightweight View, which is very simple to use:
MViewStub = (ViewStub) this. findViewById (R. id. viewstub );
MViewStub. inflate ();
It is an invisible control that occupies a very small amount of resources and does not occupy the layout. It is equivalent to a placeholder control ". In use, you can specify a layout for ViewStub. In Inflate layout, only ViewStub will be initialized. Then, when ViewStub is set to visible or ViewStub is called. when inflate () is used, the layout pointed to by ViewStub is instantiated by inflate, and the layout file replaces the current ViewStub directly, then, the layout attributes (layout_margin *** and layout_width) of ViewStub are transmitted to the layout to which it points. In this way, you can use ViewStub to dynamically display the layout during runtime to save memory resources.
The following describes the implementation principle of the inflate () method from the ViewStub source code:
public View inflate() { final ViewParent viewParent = getParent(); if (viewParent != null && viewParent instanceof ViewGroup) { if (mLayoutResource != 0) { final ViewGroup parent = (ViewGroup) viewParent; final LayoutInflater factory; if (mInflater != null) { factory = mInflater; } else { factory = LayoutInflater.from(mContext); } final View view = factory.inflate(mLayoutResource, parent, false); if (mInflatedId != NO_ID) { view.setId(mInflatedId); } final int index = parent.indexOfChild(this); parent.removeViewInLayout(this); final ViewGroup.LayoutParams layoutParams = getLayoutParams(); if (layoutParams != null) { parent.addView(view, index, layoutParams); } else { parent.addView(view, index); } mInflatedViewRef = new WeakReference
(view); if (mInflateListener != null) { mInflateListener.onInflate(this, view); } return view; } else { throw new IllegalArgumentException(ViewStub must have a valid layoutResource); } } else { throw new IllegalStateException(ViewStub must have a non-null ViewGroup viewParent); } }
Let's start with the method entry:
1. In row 2nd, the first step is to obtain the parent view object of ViewStub.
2. At the beginning of Row 3, the system will surely be able to enter the judgment. mLayoutResource is the layout resource that requires inflate, and then fill in the layout resource in Row 3.
3. In the second line, it is important to come, parent. removeViewInLayout (this); what does this code mean? You can see the method name. this indicates the ViewStub object, which means to remove the current ViewStub object from the parent view.
4. Then 23rd ~ The 28 rows are used to obtain the LayoutParams layout parameter object of ViewStub. If yes, assign it to the layout object of inflate and add the layout object of inflate to the parent view.
5. Finally, the inflate layout object is returned.
We can see from the above that when we call ViewStub for the second time. when the inflate () method is used, because the ViewStub object has been removed, in rows 2nd and 4, the obtained viewParent is null. In this case, an IllegalStateException exception will be thrown through else during the judgment: viewStub must have a non-null ViewGroup viewParent.
Notes:
1. viewStub is often referred to as "delayed loading" because in most cases, the program does not need to display the layout file pointed to by ViewStub. Only under some specific conditions, in this case, the layout file pointed to by ViewStub needs to be inflate, and the layout file directly replaces the current ViewStub, specifically through viewStub. infalte () or viewStub. setVisibility (View. VISIBLE.
2. it is very important to correctly grasp the application scenarios of ViewStub, because ViewStub can be used to optimize the layout. Generally, when the current layout or control is used by a small number of users, this can improve performance and save memory, accelerate page rendering.
3. the inflate operation on ViewStub can only be performed once, because inflate instantiates the layout it points to and replaces the current ViewStub itself (which reflects the "Placeholder" nature of ViewStub ), once replaced, no ViewStub control exists in the original layout file. Therefore, if you perform infalte on ViewStub multiple times, the following error message is displayed: viewStub must have a non-null ViewGroup viewParent.
The layout file pointed to by ViewStub mentioned in 4.3 parses inflate and replaces the current ViewStub itself. It is not completely replaced (not the same as the include tag, the layout params of the layout file is based on ViewStub, and other layout attributes are based on the layout file itself.
5. ViewStub itself is invisible. ViewStub. setVisibility (int visibility) is different from other View controls. We can look at the role of ViewStub. setVisibility () method from the source code perspective:
This method sets setVisibility () of ViewStub to View. if it is used for the first time, the system will automatically inflate the layout file to which it points and replace ViewStub itself. If it is used again, it is equivalent to setting the visibility of the layout file to which it points.
Well, there are so many principles. Let's take a look at how the code is implemented:
First take a look:
Activity_main.xml of ViewStub is used:
Hide_layout.xml
Code file:
Public class MainActivity extends ActionBarActivity {private ViewStub mViewStub; private Switch mSwitch; private boolean flag = false; @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); mViewStub = (ViewStub) this. findViewById (R. id. viewstub); // instantiate ViewStubmSwitch = (Switch) findViewById (R. id. swititch); mSwitch. setOnChecke DChangeListener (new OnCheckedChangeListener () {@ Overridepublic void onCheckedChanged (CompoundButton buttonView, boolean isChecked) {if (! Flag) {mViewStub. inflate (); // ViewStub can only be inflate once, a View object filled with resources will be returned // mViewStub. setVisibility (View. VISIBLE);) flag = true;} else {mViewStub. setVisibility (View. VISIBLE);} Button mBtn = (Button) findViewById (R. id. hide_layout_btn); // The control mBtn in the layout where ViewStub is replaced. setOnClickListener (new OnClickListener () {@ Overridepublic void onClick (View v) {Toast. makeText (getApplicationContext (), Click me !, Toast. LENGTH_SHORT). show () ;}});} else {mViewStub. setVisibility (View. GONE );}}});}}
Note: use the control in the layout replaced by ViewStub to directly findViewById.
Finally, we can extend the labels that are commonly used in Layout Optimization:
1. layout Reuse You can use this tag to directly load external xml into the current structure, which is a common tag for reusing UI resources.
Labels can reuse layout files. Simple usage is as follows:
Use the controls in the layout file of the include label to directly use findViewById.
2. Reduce view levels
Tags play an important role in UI structure optimization. They can delete redundant levels and optimize the UI. It is often used to replace FrameLayout (because the root nodes of all Activity views are FrameLayout. If the root node of the current layout is Framelayout, you can replace it with merge to reduce unnecessary layers) or when one layout contains another, Labels remove unnecessary view groups in the view hierarchy. For example, if your main layout file is vertical and include introduces a vertical layout, it makes no sense if the include layout uses LinearLayout. If it is used, it slows down your UI rendering. You can use Tags are optimized.