Android uses ViewStub to improve layout performance

Android uses ViewStub to improve layout performance

[[171874]]

In Android development, View is a technology that we must use for display. Usually, as the View becomes more and more complex, the performance of the overall layout will also decrease. Here is a View that improves layout performance in some scenarios, which is ViewStub.

What is ViewStub

  • ViewStub is a subclass of View
  • It is invisible and has a size of 0
  • Used to delay loading of layout resources

Note: Explanation of Stub

A stub is a small program routine that substitutes for a longer program, possibly to be loaded later or that is located remotely

In Java, a stub is code that replaces associated code or unimplemented code.

ViewStub usage scenarios

As shown in the figure above,

  • A ListView contains items such as news, business, technology, etc.
  • Each Item contains its own corresponding sub-topic.
  • However, the subtopic View (blue area) only needs to be loaded when the expand button is clicked.
  • If the subtopic View is loaded by default, it will cause memory usage and CPU consumption

So, ViewStub comes in handy at this time. Using ViewStub can delay loading layout resources.

How to use ViewStub

1. Use the ViewStub tag in the layout file

  1. <? xml   version = "1.0"   encoding = "utf-8" ?>  
  2. < RelativeLayout  
  3. xmlns:android = "http://schemas.android.com/apk/res/android"  
  4. xmlns:tools = "http://schemas.android.com/tools"  
  5. android:layout_width = "match_parent"  
  6. android:layout_height = "match_parent"  
  7. android:paddingLeft = "@dimen/activity_horizontal_margin"  
  8. android:paddingRight = "@dimen/activity_horizontal_margin"  
  9. android:paddingTop = "@dimen/activity_vertical_margin"  
  10. android:paddingBottom = "@dimen/activity_vertical_margin"  
  11. tools:context = "com.droidyue.viewstubsample.MainActivity" >  
  12.  
  13. < Button  
  14. android:id = "@+id/clickMe"  
  15. android:text = "Hello World!"  
  16. android:layout_width = "wrap_content"  
  17. android:layout_height = "wrap_content" />  
  18.      
  19. < ViewStub  
  20. android:id = "@+id/myViewStub"  
  21. android:inflatedId = "@+id/myInflatedViewId"  
  22. android:layout = "@layout/include_merge"  
  23. android:layout_width = "wrap_content"  
  24. android:layout_height = "wrap_content"  
  25. android:layout_below = "@id/clickMe"  
  26. />  
  27. </RelativeLayout>  

2. Inflate layout in code

  1. ViewStub myViewStub = (ViewStub)findViewById(R.id.myViewStub);
  2. if (myViewStub != null) {
  3. myViewStub.inflate();
  4. //Or load it in the following form
  5. //myViewStub.setVisibility(View.VISIBLE);
  6. }

About ViewStub

  • In addition to the inflate method, we can also call the setVisibility() method to load the layout file.
  • Once the layout is loaded, the ViewStub will be removed from the current layout hierarchy.
  • android:id specifies the ViewStub ID, which is used to find the ViewStub for lazy loading
  • android:layout delays loading of layout resource id
  • android:inflatedId The id of the loaded layout is overwritten, here is the id of RelativeLayout

Disadvantages of ViewStub

There is such a description in the official document

Note: One drawback of ViewStub is that it doesn't currently support the tag in the layouts to be inflated.

This means that ViewStub does not support Label.

About not supporting To verify the degree of labeling, we conduct a simple verification

Verification 1: Direct labeling

As follows, we have a layout file named merge_layout.xml

  1. < merge   xmlns:android = "http://schemas.android.com/apk/res/android" >  
  2.  
  3. < Button              android:layout_width = "fill_parent"  
  4. android:layout_height = "wrap_content"  
  5. android:text = "Yes" />  
  6.  
  7. < Button              android:layout_width = "fill_parent"  
  8. android:layout_height = "wrap_content"  
  9. android:text = "No" />  
  10.  
  11. </ merge >  

After replacing the android:layout attribute value of the corresponding ViewStub, the following crash is generated after running (clicking the Button button)

  1. E AndroidRuntime: android.view.InflateException: Binary XML file line #1: < merge   /> can be used only with a valid ViewGroup root and attachToRoot = true  
  2. E AndroidRuntime: at android.view.LayoutInflater.inflate(LayoutInflater.java:551)
  3. E AndroidRuntime: at android.view.LayoutInflater.inflate(LayoutInflater.java:429)
  4. E AndroidRuntime: at android.view.ViewStub.inflate(ViewStub.java:259)
  5. E AndroidRuntime: at com.droidyue.viewstubsample.MainActivity$1.onClick(MainActivity.java:20)
  6. E AndroidRuntime: at android.view.View.performClick(View.java:5697)
  7. E AndroidRuntime: at android.widget.TextView.performClick(TextView.java:10815)
  8. E AndroidRuntime: at android.view.View$PerformClick.run(View.java:22526)
  9. E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:739)
  10. E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95)
  11. E AndroidRuntime: at android.os.Looper.loop(Looper.java:158)
  12. E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7237)
  13. E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
  14. E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
  15. E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
  16. E AndroidRuntime: Caused by: android.view.InflateException: < merge   /> can be used only with a valid ViewGroup root and attachToRoot = true  
  17. E AndroidRuntime: at android.view.LayoutInflater.inflate(LayoutInflater.java:491)
  18. E AndroidRuntime: ... 13 more

Visible, direct Tags and ViewStub are not supported.

Verify the indirect ViewStub

The following layout indirectly uses the merge tag. The file name is include_merge.xml

  1. <? xml   version = "1.0"   encoding = "utf-8" ?>  
  2. < LinearLayout   xmlns:android = "http://schemas.android.com/apk/res/android"  
  3. android:orientation = "vertical"  
  4. android:layout_width = "match_parent"  
  5. android:layout_height = "match_parent" >  
  6. < include   layout = "@layout/merge_layout" />  
  7. </LinearLayout>  

Then modify the android:layout value of ViewStub and run it. Everything should be normal.

In addition, this example also verifies that ViewStub is also Good tag support.

A little code analysis about ViewStub

inflate vs setVisibility

The common point between inflate and setVisibility is that they can both load layouts

  1. /** * When visibility is set to {@link #VISIBLE} or {@link #INVISIBLE},
  2. * {@link #inflate()} is invoked and this StubbedView is replaced in its parent
  3. * by the inflated layout resource.
  4. *
  5. * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
  6. *
  7. * @see #inflate()
  8. */
  9. @Override
  10. public void setVisibility(int visibility) {
  11. if (mInflatedViewRef != null) {
  12. View view = mInflatedViewRef .get();
  13. if (view != null) {
  14. view.setVisibility(visibility);
  15. } else {
  16. throw new IllegalStateException("setVisibility called on un-referenced view");
  17. }
  18. } else {
  19. super.setVisibility(visibility);
  20. if ( visibility == VISIBLE || visibility == INVISIBLE) {
  21. inflate();
  22. }
  23. }
  24. }

setVisibility only calls the inflate method when ViewStub is first lazily initialized and visibility is not GONE.

inflate source code

By reading the following inflate method implementation, we will better understand

  • Purpose of android:inflatedId
  • ViewStub is removed from the view hierarchy after initialization.
  • ViewStub layoutParameters application
  • mInflatedViewRef establishes the connection between ViewStub and the loaded View through weak reference.

  1. /** * Inflates the layout resource identified by {@link #getLayoutResource()}
  2. * and replaces this StubbedView in its parent by the inflated layout resource.
  3. *
  4. * @return The inflated layout resource.
  5. *
  6. */
  7. public View inflate() {
  8. final ViewParent viewParent = getParent ();
  9.  
  10. if (viewParent != null && viewParent instanceof ViewGroup) {
  11. if (mLayoutResource != 0) {
  12. final ViewGroup parent = (ViewGroup) viewParent;
  13. final LayoutInflater factory = LayoutInflater .from(mContext);
  14. final View view = factory .inflate(mLayoutResource, parent,
  15. false);
  16.  
  17. if (mInflatedId != NO_ID) {
  18. view.setId(mInflatedId);
  19. }
  20.  
  21. final int index = parent .indexOfChild(this);
  22. parent.removeViewInLayout(this);
  23.  
  24. final ViewGroup.LayoutParams layoutParams = getLayoutParams ();
  25. if (layoutParams != null) {
  26. parent.addView(view, index, layoutParams);
  27. } else {
  28. parent.addView(view, index);
  29. }
  30.  
  31. mInflatedViewRef = new WeakReference < View > (view);
  32.  
  33. if (mInflateListener != null) {
  34. mInflateListener.onInflate(this, view);
  35. }
  36.  
  37. return view;
  38. } else {
  39. throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
  40. }
  41. } else {
  42. throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
  43. }
  44. }

<<:  Guide for the National Day holiday, Youji uses VR to give you a different kind of fun

>>:  ASUS's unique aesthetics of technology and art

Recommend

Brand Marketing: Let’s talk about Durex’s 419 marketing failure!

On April 19, Durex Weibo posted several interacti...

Xiaomi is on the left and Meizu is on the right

Meizu has been waiting for a long time for the op...

How to build private domain traffic from 0 to 1

In recent years, private domain traffic has been ...

To B & To C: Are the operations of To B products really different?

Common concepts of To B operations and To C opera...

Baidu bidding promotion optimization strategy

As the market and epidemic continue to change, ma...

If the corals are gone, where will the crabs attach themselves to?

At present, global climate change, especially glo...

Why is Silicon Valley the only one that can combat fake news?

According to foreign media reports, as social net...

It's outrageous: I'm 165cm tall and weigh 80kg, but I have fatty liver...

During the physical examination at the end of the...