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

Is the Turing test still relevant today?

Source: Dark Matter Articles/medium *This article...

Where does the last drop of seawater disappear in the Himalayas?

Qinghai-Tibet Plateau It is the best place to stu...

Dizziness "first reaction": Is it Meniere's?

For many friends who suddenly feel dizzy, their f...

Is low-carbon investment worth looking forward to?

The oil and gas landscape is changing. The indust...

Google officially pushes the official version of Android 10.0!

As previously revealed, Google officially pushed ...

400 phone applications can be processed online directly

Now when we help you with the phone number, a com...

How much does a box of Niraparib cost? How much does a box of Niraparib cost?

How much does a box of Niraparib cost? How much d...

With a limited budget, how can we make the product spread itself?

Here's a question for you: what's your un...