[[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 - <? xml version = "1.0" encoding = "utf-8" ?>
- < RelativeLayout
- xmlns:android = "http://schemas.android.com/apk/res/android"
- xmlns:tools = "http://schemas.android.com/tools"
- android:layout_width = "match_parent"
- android:layout_height = "match_parent"
- android:paddingLeft = "@dimen/activity_horizontal_margin"
- android:paddingRight = "@dimen/activity_horizontal_margin"
- android:paddingTop = "@dimen/activity_vertical_margin"
- android:paddingBottom = "@dimen/activity_vertical_margin"
- tools:context = "com.droidyue.viewstubsample.MainActivity" >
-
- < Button
- android:id = "@+id/clickMe"
- android:text = "Hello World!"
- android:layout_width = "wrap_content"
- android:layout_height = "wrap_content" />
-
- < ViewStub
- android:id = "@+id/myViewStub"
- android:inflatedId = "@+id/myInflatedViewId"
- android:layout = "@layout/include_merge"
- android:layout_width = "wrap_content"
- android:layout_height = "wrap_content"
- android:layout_below = "@id/clickMe"
- />
- </RelativeLayout>
2. Inflate layout in code - ViewStub myViewStub = (ViewStub)findViewById(R.id.myViewStub);
- if (myViewStub != null) {
- myViewStub.inflate();
- //Or load it in the following form
- //myViewStub.setVisibility(View.VISIBLE);
- }
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 - < merge xmlns:android = "http://schemas.android.com/apk/res/android" >
-
- < Button android:layout_width = "fill_parent"
- android:layout_height = "wrap_content"
- android:text = "Yes" />
-
- < Button android:layout_width = "fill_parent"
- android:layout_height = "wrap_content"
- android:text = "No" />
-
- </ merge >
After replacing the android:layout attribute value of the corresponding ViewStub, the following crash is generated after running (clicking the Button button) - E AndroidRuntime: android.view.InflateException: Binary XML file line #1: < merge /> can be used only with a valid ViewGroup root and attachToRoot = true
- E AndroidRuntime: at android.view.LayoutInflater.inflate(LayoutInflater.java:551)
- E AndroidRuntime: at android.view.LayoutInflater.inflate(LayoutInflater.java:429)
- E AndroidRuntime: at android.view.ViewStub.inflate(ViewStub.java:259)
- E AndroidRuntime: at com.droidyue.viewstubsample.MainActivity$1.onClick(MainActivity.java:20)
- E AndroidRuntime: at android.view.View.performClick(View.java:5697)
- E AndroidRuntime: at android.widget.TextView.performClick(TextView.java:10815)
- E AndroidRuntime: at android.view.View$PerformClick.run(View.java:22526)
- E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:739)
- E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95)
- E AndroidRuntime: at android.os.Looper.loop(Looper.java:158)
- E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7237)
- E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
- E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
- E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
- E AndroidRuntime: Caused by: android.view.InflateException: < merge /> can be used only with a valid ViewGroup root and attachToRoot = true
- E AndroidRuntime: at android.view.LayoutInflater.inflate(LayoutInflater.java:491)
- 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 - <? xml version = "1.0" encoding = "utf-8" ?>
- < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
- android:orientation = "vertical"
- android:layout_width = "match_parent"
- android:layout_height = "match_parent" >
- < include layout = "@layout/merge_layout" />
- </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 - /** * When visibility is set to {@link #VISIBLE} or {@link #INVISIBLE},
- * {@link #inflate()} is invoked and this StubbedView is replaced in its parent
- * by the inflated layout resource.
- *
- * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
- *
- * @see #inflate()
- */
- @Override
- public void setVisibility(int visibility) {
- if (mInflatedViewRef != null) {
- View view = mInflatedViewRef .get();
- if (view != null) {
- view.setVisibility(visibility);
- } else {
- throw new IllegalStateException("setVisibility called on un-referenced view");
- }
- } else {
- super.setVisibility(visibility);
- if ( visibility == VISIBLE || visibility == INVISIBLE) {
- inflate();
- }
- }
- }
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.
- /** * Inflates the layout resource identified by {@link #getLayoutResource()}
- * and replaces this StubbedView in its parent by the inflated layout resource.
- *
- * @return The inflated layout resource.
- *
- */
- public View inflate() {
- final ViewParent viewParent = getParent ();
-
- if (viewParent != null && viewParent instanceof ViewGroup) {
- if (mLayoutResource != 0) {
- final ViewGroup parent = (ViewGroup) viewParent;
- final LayoutInflater 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 > (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");
- }
- }
|