2019独角兽企业重金招聘Python工程师标准>>>

1.重用布局文件

1.)include标签

首先用得最多的应该是include,按照官方的意思,include就是为了解决重复定义相同布局的问题。使用起来很方便,我这里就不举例子。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/my_title_parent_id"   android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical" >  <include android:id="@+id/my_title_ly"  layout="@layout/titlebar" />  </LinearLayout>  

注意事项:

1.如果你只想单独修改某个布局文件的titleBar而其他布局文件的titleBar不受影响的话,我们可以使用覆写<include>属性的方式

在<include>标签当中,我们是可以覆写所有layout属性的,即include中指定的layout属性将会覆盖掉titlebar中根视图指定的layout属性。因此,这里我们希望将titlebar的高度设置成wrap_content,就可以这样写:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/my_title_parent_id"   android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical" >  <include  android:id="@+id/my_title_ly"  android:layout_width="match_parent"  android:layout_height="wrap_content"  layout="@layout/titlebar" />  </LinearLayout>  

而非layout属性则无法在<include>标签当中进行覆写。另外需要注意的是,如果我们想要在<include>标签当中覆写layout属性,必须要将layout_width和layout_height这两个属性也进行覆写,否则覆写效果将不会生效。

2.使用include最常见的问题就是findViewById查找不到目标控件,这个问题出现的前提是在include时设置了id,而在findViewById时却用了被include进来的布局的根元素id。例如上述例子中,include时设置了该布局的id为my_title_ly,而my_title_layout.xml中的根视图的id为my_title_parent_id。此时如果通过findViewById来找my_title_parent_id这个控件,然后再查找my_title_parent_id下的子控件则会抛出空指针。代码如下 :

View titleView = findViewById(R.id.my_title_parent_id) ;
// 此时 titleView 为空,找不到。此时空指针TextView titleTextView = (TextView)titleView.findViewById(R.id.title_tv) ;
titleTextView.setText("new Title");  

正确的方式:

// 使用include时设置的id,即R.id.my_title_ly
View titleView = findViewById(R.id.my_title_ly) ;
// 通过titleView找子控件
TextView titleTextView = (TextView)titleView.findViewById(R.id.title_tv) ;
titleTextView.setText("new Title");  

或者更简单的直接查找它的子控件:

TextView titleTextView = (TextView)findViewById(R.id.title_tv) ;
titleTextView.setText("new Title");

通过看源码出现这样的原因是:解析过程中会首先判断include标签的id如果不是View.NO_ID的话会把该id设置给被引入的布局根元素的id,即此时在我们的例子中被引入的id为my_title_parent_id的根元素RelativeLayout的id被设置成了include标签中的id,即RelativeLayout的id被动态修改成了”my_title_ly”。因此此时我们再通过“my_title_parent_id”这个id来查找根元素就会找不到了! 
所以结论就是: 如果include中设置了id,那么就通过include的id来查找被include布局根元素的View;如果include中没有设置Id, 而被include的布局的根元素设置了id,那么通过该根元素的id来查找该view即可。拿到根元素后查找其子控件都是一样的。

2.)Merge标签

<merge>标签是作为<include>标签的一种辅助扩展来使用的,它的主要作用是为了防止在引用布局文件时产生多余的布局嵌套。大家都知道,Android去解析和展示一个布局是需要消耗时间的,布局嵌套的越多,那么解析起来就越耗时,性能也就越差,因此我们在编写布局文件时应该让嵌套的层数越少越好。

比如我们写一个公共的确定和取消按钮ok_cancel_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:orientation="vertical" >  <Button  android:id="@+id/ok"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_marginLeft="20dp"  android:layout_marginRight="20dp"  android:text="OK" />  <Button  android:id="@+id/cancel"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_marginLeft="20dp"  android:layout_marginRight="20dp"  android:layout_marginTop="10dp"  android:text="Cancel" />  </LinearLayout>  

然后再另一个界面main.xml去引用

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical" >  <EditText  android:id="@+id/edit"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_marginBottom="10dp"  android:layout_marginLeft="20dp"  android:layout_marginRight="20dp"  android:layout_marginTop="10dp"  android:hint="Edit something here" />  <include layout="@layout/ok_cancel_layout"/>  </LinearLayout>  

目前main.xml这个界面当中其实已经存在着多余的布局嵌套了!感觉还没写几行代码呢,怎么这就已经有多余的布局嵌套了?不信的话我们可以通过View Hierarchy工具来查看一下,如下图所示:

相信大家已经可以看出来了吧,这个内部的LinearLayout就是一个多余的布局嵌套,实际上并不需要这样一层,让两个按钮直接包含在外部的LinearLayout当中就可以了。而这个多余的布局嵌套其实就是由于布局引入所导致的,那么应该怎样优化掉这个问题呢?当然就是使用<merge>标签来完成了,修改ok_cancel_layout.xml中的代码,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">  <Button  android:id="@+id/ok"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_marginLeft="20dp"  android:layout_marginRight="20dp"  android:text="OK" />  <Button  android:id="@+id/cancel"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_marginLeft="20dp"  android:layout_marginRight="20dp"  android:layout_marginTop="10dp"  android:text="Cancel" />  </merge>  

我们在通过View Hierarchy工具来查看一下,如下图所示:

可以看到,这里我们将ok_cancel_layout最外层的LinearLayout布局删除掉,换用了<merge>标签,这就表示当有任何一个地方去include这个布局时,会将<merge>标签内包含的内容直接填充到include的位置,不会再添加任何额外的布局结构.

让我意想不到的是Merge竟然是个activity,并且还动态的加载了LinearLayout对象.

/** * Exercise <merge /> tag in XML files. */
public class Merge extends Activity {  private LinearLayout mLayout;  @Override  protected void onCreate(Bundle icicle) {  super.onCreate(icicle);  mLayout = new LinearLayout(this);  mLayout.setOrientation(LinearLayout.VERTICAL);  LayoutInflater.from(this).inflate(R.layout.merge_tag, mLayout);  setContentView(mLayout);  }  public ViewGroup getLayout() {  return mLayout;  }
}  

通过看源码发现:在解析的过程中,如果是merge标签,那么第一步:首先获取merge标签的parent ,第二步:获取布局参数 ,第三部:递归解析每个子元素 ,第四步:将子元素直接添加到merge标签的parent view中 ,这样就保证了不会引入额外的层级。
3.)ViewStub标签

根据官方的解释大致可翻译成:其实ViewStub就是一个宽高都为0的一个View,它默认是不可见的,只有通过调用setVisibility函数或者Inflate函数才会将其要装载的目标布局给加载出来,从而达到延迟加载的效果,这个要被加载的布局通过android:layout属性来设置。

有的时候我们会遇到这样的场景,就是某个布局当中的元素非常多,但并不是所有元素都一起显示出来的,而是普通情况下只显示部分常用的元素,而那些不常用的元素只有在用户进行特定操作的情况下才会显示出来。

这里举个大家都非常熟悉的例子,我们在添加联系人的时候其实可以编辑的字段真的非常多,姓名、电话、email、传真、住址、昵称等等等等,但其实基本上大家最常用的就是填一个姓名,填一个电话而已。那么将这么多繁杂的字段都一起显示在界面上其实并不是一种很好的做法,因为大多数人都是用不到这些字段的。比较聪明的做法就是把最常用的姓名和电话显示在界面上,然后给用户提供一个添加更多字段的选项,当用户真的有需要去添加其它信息的时候,我们才将另外的元素显示到界面上。

说到实现这样一个功能,我相信大多数人的第一反应就是将不常用的元素使用INVISIBLE或者GONE进行隐藏,然后当用户需要使用这些元素的时候再把它们置成VISIBLE显示出来。使用这种方式肯定可以实现功能的,但是性能方面就表现得一般了,因为即使是将元素进行隐藏,它们其实还是在布局当中的,每个元素还拥有着自己的宽、高、背景等等属性,解析布局的时候也会将这些隐藏的元素一一解析出来。

那么我们如何才能让这些不常用的元素仅在需要时才去加载呢?Android为此提供了一种非常轻量级的控件,ViewStub。ViewStub虽说也是View的一种,但是它没有大小,没有绘制功能,也不参与布局,资源消耗非常低,将它放置在布局当中基本可以认为是完全不会影响性能的。

还是举例说明例子1:比如我们在添加三个EditText构成另一个布局edittext_extra_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical" >  <EditText  android:id="@+id/edit_extra1"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_marginLeft="20dp"  android:layout_marginRight="20dp"  android:hint="Extra field 1" />  <EditText  android:id="@+id/edit_extra2"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_marginLeft="20dp"  android:layout_marginRight="20dp"  android:layout_marginTop="10dp"  android:hint="Extra field 2" />  <EditText  android:id="@+id/edit_extra3"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_marginLeft="20dp"  android:layout_marginRight="20dp"  android:layout_marginTop="10dp"  android:hint="Extra field 3" />  </LinearLayout>  

接下来我们修改main.xml文件中的代码,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical" >  <EditText  android:id="@+id/edit"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_marginBottom="10dp"  android:layout_marginLeft="20dp"  android:layout_marginRight="20dp"  android:layout_marginTop="10dp"  android:hint="@string/edit_something_here" />  <Button  android:id="@+id/more"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:layout_gravity="right"  android:layout_marginRight="20dp"  android:layout_marginBottom="10dp"  android:text="More" />  <ViewStub   android:id="@+id/view_stub"  android:layout="@layout/profile_extra"  android:layout_width="match_parent"  android:layout_height="wrap_content"  />  <include layout="@layout/ok_cancel_layout" />  </LinearLayout>  

可以看到,这里我们新增了一个More Button,这个按钮就是用于去加载那些不常用的元素的,然后在Button的下面定义了一个ViewStub。在ViewStub控件中,我们先是通过id属性给它指定了一个唯一标识,又通过layout属性将profile_extra布局传入进来,接着给ViewStub指定了一个宽高。注意,虽然ViewStub是不占用任何空间的,但是每个布局都必须要指定layout_width和layout_height属性,否则运行就会报错。

private EditText editExtra1;
private EditText editExtra2;
private EditText editExtra3;  public void onMoreClick() {  ViewStub viewStub = (ViewStub) findViewById(R.id.view_stub);  if (viewStub != null) {  View inflatedView = viewStub.inflate();  editExtra1 = (EditText) inflatedView.findViewById(R.id.edit_extra1);  editExtra2 = (EditText) inflatedView.findViewById(R.id.edit_extra2);  editExtra3 = (EditText) inflatedView.findViewById(R.id.edit_extra3);  }
}  

调用inflate()方法之后会将加载出来的布局进行返回,之后我们就可以对这个布局进行任意的操作了,再次隐藏显示,或者获取子元素的实例等。注意这里我对ViewStub的实例进行了一个非空判断,这是因为ViewStub在XML中定义的id只在一开始有效,一旦ViewStub中指定的布局加载之后,这个id也就失败了,那么此时findViewById()得到的值也会是空。

例子2

<ViewStub  android:id="@+id/stub_import"  android:inflatedId="@+id/stub_comm_lv"  android:layout="@layout/my_comment_layout"  android:layout_width="fill_parent"  android:layout_height="wrap_content"  android:layout_gravity="bottom" /  
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:id="@+id/my_comm_lv"  android:layout_height="match_parent" >  </ListView>  
public class MainActivity extends Activity {  public void onCreate(Bundle b){  // main.xml中包含上面的ViewStub  setContentView(R.layout.main);  // 方式1,获取ViewStub,  ViewStub listStub = (ViewStub) findViewById(R.id.stub_import);  // 加载评论列表布局  listStub.setVisibility(View.VISIBLE);  // 获取到评论ListView,注意这里是通过ViewStub的inflatedId来获取  ListView commLv = findViewById(R.id.stub_comm_lv);  if ( listStub.getVisibility() == View.VISIBLE ) {  // 已经加载, 否则还没有加载  }  }  }  

通过setVisibility(View.VISIBILITY)来加载评论列表,此时你要获取到评论ListView对象的话,则需要通过findViewById来查找,而这个id并不是ViewStub的id。 
这是为什么呢 ?

通过看源码原因是:

1、加载目标布局

2、如果ViewStub的inflatedId不是NO_ID则把inflatedId设置为目标布局根元素的id,即评论ListView的id

3、将ViewStub自身从parent中移除
4、将目标布局的根元素添加到parent中

public class MainActivity extends Activity {  // 把commLv2设置为类的成员变量  ListView commLv2 = null;  //  public void onCreate(Bundle b){  // main.xml中包含上面的ViewStub  setContentView(R.layout.main);  // 方式二  ViewStub listStub2 = (ViewStub) findViewById(R.id.stub_import) ;  // 成员变量commLv2为空则代表未加载  if ( commLv2 == null ) {  // 加载评论列表布局, 并且获取评论ListView,inflate函数直接返回ListView对象  commLv2 = (ListView)listStub2.inflate();  } else {  // ViewStub已经加载  }  }  }  
  1. 判断是否已经加载过, 如果通过setVisibility来加载,那么通过判断可见性即可;如果通过inflate()来加载是不可以通过判断可见性来处理的,而需要使用方式2来进行判断。
  2. findViewById的问题,注意ViewStub中是否设置了inflatedId,如果设置了则需要通过inflatedId来查找目标布局的根元素。

转载于:https://my.oschina.net/quguangle/blog/1218057

性能优化--布局优化技巧相关推荐

  1. android布局优化方案,Android启动优化-布局优化

    Android启动优化-布局优化 安卓应用开发发展到今天,已经成为一个非常成熟的技术方向,从目前的情况看,安卓开发还是一个热火朝天的发展,但高级人才却相对较少,如今移动互联网的开发者也逐渐开始注重插入 ...

  2. Android 性能优化——布局优化

    布局优化:就是尽量减少布局文件的层级,致使Android的绘制的工作量减少了,性能就提高啦. 第一种 首先删除布局中无用的控件和层级,其次有选择性的使用性能较低的ViewGroup. 比如Relati ...

  3. Android 布局优化

    在开发过程中我们经常说性能优化,但性能优化是一个比较宽泛的概念.在Android开发中性能优化可能包括:Java代码优化, 算法优化, SQLite优化, 布局优化等.那么这篇博客就来总结并分享下An ...

  4. android 重用布局区分控件,【专题分析】布局优化

    [TOC] # 布局优化 布局优化的思想很简单,就是尽量减少布局文件的层级.主要从以下几个方面入手: * 善于重用布局文件 * 使用ViewStub仅在需要时才加载 * 删除无用的控件和布局 * 使用 ...

  5. Android开发——布局性能优化的一些技巧(一)

    0. 前言 上一篇我们分析了为什么LinearLayout会比RelativeLayout性能更高,意义在于分析了这两种布局的实现源码,算是对一个小结论的证明过程,但是对布局性能的优化效果,对这两种布 ...

  6. 前端性能优化的一些技巧(90% chatGpt生成)

    终于弄好了chatGpt的账号,赶紧来体验一波. 先来一波结论,这篇文章的主要内容来源,90%是用chatGpt生成的. 先上chatGpt的生成的结果: 作为一名懒惰的程序员,chatGpt会帮助我 ...

  7. 优化Android App性能?十大技巧

    优化Android App性能?十大技巧 android shangxuetang 1年前 (2014-05-27) 3399℃ 4评论 android 无论锤子还是茄子手机的不断冒出,Android ...

  8. Android性能优化:手把手教你如何让App更快、更稳、更省(含内存、布局优化等)...

    2019独角兽企业重金招聘Python工程师标准>>> 前言 在 Android开发中,性能优化策略十分重要 因为其决定了应用程序的开发质量:可用性.流畅性.稳定性等,是提高用户留存 ...

  9. mysql 改表面_MySQL_解析MySQL数据库性能优化的六大技巧,数据库表表面上存在索引和防 - phpStudy...

    解析MySQL数据库性能优化的六大技巧 数据库表表面上存在索引和防错机制,然而一个简单的查询就会耗费很长时间.Web应用程序或许在开发环境中运行良好,但在产品环境中表现同样糟糕.如果你是个数据库管理员 ...

最新文章

  1. HTML5本地存储localStorage,sessionStorage
  2. JDFlipNumberView
  3. 程序员编程艺术:第三章续、Top K算法问题的实现
  4. 中功率继电器行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  5. 宏碁推智能佛珠,修养心性也可数据化
  6. 解决AndroidStudio更新后在 Building gradle project info 一直卡住
  7. LCD1602液晶显示屏驱动文件
  8. Java Web九大内置对象及四大域对象
  9. 【JZOJ4587】Snow的追寻 题解
  10. matlab画六面体,MATLAB绘制平行六面体
  11. 网络在线直播技术揭秘(一):编码与压缩算法
  12. 北鲲云超算平台药物发现Cloud-HPCAI解决方案助力生命科学行业
  13. MySQL进阶:触发器
  14. iphone计算机要电话,有了这个神器,在PC上也能接听iPhone电话、收发短息啦(安卓也可以哦~)...
  15. gojs开发环境去除水印
  16. 購物籃分析,最清楚概念-part1
  17. 手机操作系统开源软件
  18. 用Python操作MySQL数据库-详细指南
  19. Docker 常用命令 - 镜像与容器
  20. esp32第一篇:试用

热门文章

  1. [BUUCTF-pwn]——pwn1_sctf_2016
  2. c语言链表查找的代码与题目,链表的C语言实现之单链表的查找运算_c语言
  3. html中颜色的编号,html中各种颜色的编号.doc
  4. Java解析XML汇总(DOM/SAX/JDOM/DOM4j/XPath)
  5. oracle插入回车换行符
  6. Hibernate配置属性详解
  7. 自己在UWP程序上调用usb转串口的路程
  8. 零基础逆向工程28_Win32_02_事件_消息_消息处理函数
  9. continue和pass測试
  10. setTimeout 的定时器的妙用