Android ViewStub使用方法学习
前言
当渲染一个活动时,这个活动的布局可能会有很多visible为invisible和gone的情况,虽然这些控件虽然现在不显示在屏幕上,但是系统在加载这个布局文件时还是会加载它的,这就影响了这个页面的加载效率,因为这些不可见的控件提前加载它们并没有什么实际的意义,反而会减缓页面的加载时间,所以为了解决这个问题可以使用ViewStub来懒加载暂时不显示的布局.
1.ViewStub的优势
简单来说, ViewStub可以做到按需加载一个布局,我们可以控制它加载的时机,而不是在Activity的onCreate方法中去加载.即懒加载
2.ViewStub的使用
<ViewStub android:id="@+id/stub" android:inflatedId="@+id/text" android:layout="@layout/text_view_stub" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/textView3" android:layout_marginTop="180dp" android:layout_marginLeft="100dp"/>
属性 功能
android:inflatedId="@+id/text" 为我们要加载的布局提供一个id android:layout 我们需要加载的布局 除此之外
app:layout_constraintTop_toBottomOf="@id/textView3" android:layout_marginTop="180dp" android:layout_marginLeft="100dp"/>
这些代表我们懒加载的布局在父布局的位置,如果懒加载的布局有相同的属性,将会被覆盖
//通过id得到viewStub对象 ViewStub viewStub = findViewById(R.id.stub); //动态加载布局 viewStub.inflate();
简单实战
1.viewstub就是动态加载试图
也就是在我们的app启动绘制页面的时候,他不会绘制到view树中;当在代码中执行inflate操作后,她才会被添加到试图中。其实ViewStub就是一个宽高都为0的一个View,它默认是不可见的,只有通过调用setVisibility函数或者Inflate函数才 会将其要装载的目标布局给加载出来,从而达到延迟加载的效果,这个要被加载的布局通过android:layout属性来设置。最终目的是把app加载页面的速度提高了,使用户体验更好。
2.看一个简单的demo
viewstub.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/inflatedStart" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/hello_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" android:text="DATA EMPTY!"/> </android.support.constraint.ConstraintLayout>
activity_myviewstub.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"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="inflate" android:text="inflate" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="setData" android:text="setdata"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="hide" android:text="hide"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="show" android:text="show"/> <ViewStub android:id="@+id/vs" android:inflatedId="@+id/inflatedStart" android:layout="@layout/viewstub" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
MyViewStubActivity.java
package com.ysl.myandroidbase.viewstub; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.constraint.ConstraintLayout; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.ViewStub; import android.widget.TextView; import com.ysl.myandroidbase.R; public class MyViewStubActivity extends AppCompatActivity { private ViewStub viewStub; private TextView textView; private View inflate; private ConstraintLayout constraintLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_myviewstub); viewStub = findViewById(R.id.vs); //textView = (TextView) findViewById(R.id.hello_tv);空指针,因为viewstub没有inflate } public void inflate(View view){ if (inflate == null) {//inflate只会进行一次,当第二次调用的时候,就会抛异常;也可以try catch进行处理 inflate = viewStub.inflate(); constraintLayout = findViewById(R.id.inflatedStart); System.out.println(constraintLayout); System.out.println("viewStub-------->"+viewStub); textView = viewStub.findViewById(R.id.hello_tv);//获取到的textview是空的; System.out.println("viewStub textView-------->"+textView);//null textView = constraintLayout.findViewById(R.id.hello_tv); System.out.println("constraintLayout textView-------->"+textView); textView = findViewById(R.id.hello_tv); System.out.println("textView-------->"+textView); } } public void setData(View view){ if (constraintLayout != null) { textView = constraintLayout.findViewById(R.id.hello_tv); textView.setText("HAVE DATA !!!"); } } public void hide(View view){ viewStub.setVisibility(View.GONE); // if (constraintLayout != null){ // constraintLayout.setVisibility(View.GONE); // } } public void show(View view){ viewStub.setVisibility(View.VISIBLE); // if (constraintLayout != null){ // constraintLayout.setVisibility(View.VISIBLE); // } } }
3.当调用第二次inflate的时候,会报错:
编辑切换为居中
添加图片注释,不超过 140 字(可选)
我们看一下这是为什么?进入viewStub.inflate();的源码:
public View inflate() { final ViewParent viewParent = getParent(); if (viewParent != null && viewParent instanceof ViewGroup) { if (mLayoutResource != 0) { final ViewGroup parent = (ViewGroup) viewParent; final View view = inflateViewNoAdd(parent); replaceSelfWithView(view, parent); 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"); } }
可以看到当viewParent为空或者不是viewgroup时才会报这个错误;那么第一次调用的时候,肯定是进去了;发现一个方法replaceSelfWithView(view,parent);view就是我们在布局文件中给viewstub指定的layout所引用的那个布局;parent就是getParent方法得到的,也就是acticity的填充布局LinearLayout;
进去看一下:
private void replaceSelfWithView(View view, ViewGroup parent) { 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); } }
可以发现parent.removeViewInLayout(this);把this就是viewstub从父布局linearlayout中移除了;parent.addView()就是把view(也就是我们引用的布局)添加到了父布局LinearLayout中。
我们用layout inspector来查看一下:
inflate前:可以看到viewstub是灰色的
编辑
添加图片注释,不超过 140 字(可选)
inflate后:可以看到viewstub直接被移除了,把引用布局直接放到view树里了。
编辑
添加图片注释,不超过 140 字(可选)
所以当我们第二次再调用inflate方法时,viewstub的parent已经为空了;就会抛出此异常;
当调用textView = viewStub.findViewById(R.id.hello_tv);//获取到的textview是空的;
而使用textView = findViewById(R.id.hello_tv);就可以直接拿到控件对象了;
当实现引用布局的显示和隐藏时,测试发现使用viewstub的setVisibility()方法可以实现,这是为什么呢?;按理说使用constraintLayout.setVisibility()当然也可以;根据上面的view树结构来看,好像使用引用布局的setVisibility()方法更合理一些;
下面我们再来看看viewstub的setVisibility()为什么也可以;跟进源码看看:
编辑切换为居中
添加图片注释,不超过 140 字(可选)
源码中使用mInflatedViewRef获取到view,然后设置隐藏与显示;mInflatedViewRef是一个view的弱引用WeakReference
其实在上面的inflate方法中已经为其添加了mInflatedViewRef = new WeakReference<>(view);这个view就是viewstub中的引用布局;
所以,使用viewstub可以实现相同的显示或隐藏效果;
从上图的最后一个红色框中可以发现,假设现在我没有调用inflate方法,而是直接点击了show按钮;然后引用布局也可以绘制出来;这就是我在写demo的时候,直接上去点击show按钮,竟然也可以显示的原因。
编辑切换为居中
添加图片注释,不超过 140 字(可选)
以上就是Android ViewStub的使用与简单的演练;如果想要进阶自己Android技能,可以参考这份《Android核心技术笔记》里面记录有Android的核心技术与其他前沿技术。
文末
Android ViewStub的使用注意事项
inflate方法只能调用一次,再次调用会出异常 我们看下inflate方法的源码,一旦第二次调用inflate方法,我们的到viewParent将等于null,会报 throw new IllegalStateException(“ViewStub must have a non-null ViewGroup viewParent”);异常,所以总之一句话,这个懒加载只能加载一次
public View inflate() { final ViewParent viewParent = getParent(); if (viewParent != null && viewParent instanceof ViewGroup) { if (mLayoutResource != 0) { final ViewGroup parent = (ViewGroup) viewParent; final View view = inflateViewNoAdd(parent); replaceSelfWithView(view, parent); 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"); } }
以上就是Android ViewStub使用方法学习的详细内容,更多关于Android ViewStub使用的资料请关注猪先飞其它相关文章!
原文出处:https://juejin.cn/post/7165118393345900580
相关文章
- 有时为了网站安全和版权问题,会对自己写的php源码进行加密,在php加密技术上最常用的是zend公司的zend guard 加密软件,现在我们来图文讲解一下。 下面就简单说说如何...2016-11-25
- 下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
- ps软件是现在很多人都会使用到的,HSL面板在ps软件中又有着非常独特的作用。这次文章就给大家介绍下ps怎么使用HSL面板,还不知道使用方法的下面一起来看看。  ...2017-07-06
- 许多的朋友对于Plesk控制面板应用不是非常的了解特别是英文版的Plesk控制面板,在这里小编整理了一些关于Plesk控制面板常用的使用方案整理,具体如下。 本文基于Linu...2016-10-10
使用insertAfter()方法在现有元素后添加一个新元素
复制代码 代码如下: //在现有元素后添加一个新元素 function insertAfter(newElement, targetElement){ var parent = targetElement.parentNode; if (parent.lastChild == targetElement){ parent.appendChild(newEl...2014-05-31Android开发中findViewById()函数用法与简化
findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20- 如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
使用percona-toolkit操作MySQL的实用命令小结
1.pt-archiver 功能介绍: 将mysql数据库中表的记录归档到另外一个表或者文件 用法介绍: pt-archiver [OPTION...] --source DSN --where WHERE 这个工具只是归档旧的数据,不会对线上数据的OLTP查询造成太大影响,你可以将...2015-11-24- 大概有如下步骤 新建项目Bejs 新建文件package.json 新建文件Gruntfile.js 命令行执行grunt任务 一、新建项目Bejs源码放在src下,该目录有两个js文件,selector.js和ajax.js。编译后代码放在dest,这个grunt会...2014-06-07
如何使用php脚本给html中引用的js和css路径打上版本号
在搜索引擎中搜索关键字.htaccess 缓存,你可以搜索到很多关于设置网站文件缓存的教程,通过设置可以将css、js等不太经常更新的文件缓存在浏览器端,这样访客每次访问你的网站的时候,浏览器就可以从浏览器的缓存中获取css、...2015-11-24- 夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
jQuery 1.9使用$.support替代$.browser的使用方法
jQuery 从 1.9 版开始,移除了 $.browser 和 $.browser.version , 取而代之的是 $.support 。 在更新的 2.0 版本中,将不再支持 IE 6/7/8。 以后,如果用户需要支持 IE 6/7/8,只能使用 jQuery 1.9。 如果要全面支持 IE,并混合...2014-05-31- 为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
- 如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
安装和使用percona-toolkit来辅助操作MySQL的基本教程
一、percona-toolkit简介 percona-toolkit是一组高级命令行工具的集合,用来执行各种通过手工执行非常复杂和麻烦的mysql和系统任务,这些任务包括: 检查master和slave数据的一致性 有效地对记录进行归档 查找重复的索...2015-11-24- C#注释的一些使用方法浅谈,需要的朋友可以参考一下...2020-06-25
- 深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
- 一、下载 mysqlsla [root@localhost tmp]# wget http://hackmysql.com/scripts/mysqlsla-2.03.tar.gz--19:45:45-- http://hackmysql.com/scripts/mysqlsla-2.03.tar.gzResolving hackmysql.com... 64.13.232.157Conn...2015-11-24
- 目前,JSON已经成为最流行的数据交换格式之一,各大网站的API几乎都支持它。我写过一篇《数据类型和JSON格式》,探讨它的设计思想。今天,我想总结一下PHP语言对它的支持,这是开发互联网应用程序(特别是编写API)必须了解的知识...2015-10-30
- 下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02