怎样才能写出优秀的Android App,是每一个程序员追求的目标。那么怎么才能写出一个优秀的App呢?相信很多初学者也会有这种迷茫。一句话来回答这个问题:细节很重要。今天我们就从最基础的XML布局来谈谈怎么提高Android性能问题吧!

也许你经常会遇到比较复杂的布局,这种情况下,最简单的方法就是多层嵌套实现效果,但是最简单的方法是否是最优的方法呢? 这里需要打一个大大的问号?????经验告诉我们,往往简单的方法,得到的结果不是最优解,那么我们通过一个例子来研究一下怎么去优化我们的XML布局吧,下面通过经典微信中的“发现”tab页面中的布局来看看怎么实现。

上面这张图片是微信界面截图,看到这张效果图的第一眼会让开发者想到使用线性布局实现这种左边图片,右边文字,一行白色背景效果很方便。那么我们就按照一般思路写出如下布局代码:

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@color/color_eeeeee"

android:orientation="vertical"

tools:context=".MainActivity">

android:layout_width="match_parent"

android:layout_height="0dp"

android:layout_weight="1"

android:orientation="vertical">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginTop="20dp"

android:background="@drawable/item_bg_select"

android:clickable="true"

android:gravity="center_vertical"

android:orientation="horizontal"

android:paddingLeft="20dp"

android:paddingRight="20dp">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/afe" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="15dp"

android:text="@string/fiends"

android:textColor="@android:color/black"

android:textSize="16sp" />

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginTop="20dp"

android:background="@android:color/white"

android:orientation="vertical">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="@drawable/item_bg_select"

android:clickable="true"

android:gravity="center_vertical"

android:orientation="horizontal"

android:paddingLeft="20dp"

android:paddingRight="20dp">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/afg" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="15dp"

android:text="@string/scan"

android:textColor="@android:color/black"

android:textSize="16sp" />

android:layout_width="match_parent"

android:layout_height="0.5dp"

android:layout_marginLeft="10dp"

android:layout_marginRight="10dp"

android:background="@color/color_e0e0e0">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="@drawable/item_bg_select"

android:clickable="true"

android:gravity="center_vertical"

android:orientation="horizontal"

android:paddingLeft="20dp"

android:paddingRight="20dp">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/afh" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="15dp"

android:text="@string/shake"

android:textColor="@android:color/black"

android:textSize="16sp" />

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginTop="20dp"

android:background="@android:color/white"

android:orientation="vertical">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="@drawable/item_bg_select"

android:clickable="true"

android:gravity="center_vertical"

android:orientation="horizontal"

android:paddingLeft="20dp"

android:paddingRight="20dp">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/afd" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="15dp"

android:text="@string/nearby"

android:textColor="@android:color/black"

android:textSize="16sp" />

android:layout_width="match_parent"

android:layout_height="0.5dp"

android:layout_marginLeft="10dp"

android:layout_marginRight="10dp"

android:background="@color/color_e0e0e0">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="@drawable/item_bg_select"

android:clickable="true"

android:gravity="center_vertical"

android:orientation="horizontal"

android:paddingLeft="20dp"

android:paddingRight="20dp">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/afb" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="15dp"

android:text="@string/float_bottle"

android:textColor="@android:color/black"

android:textSize="16sp" />

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginTop="20dp"

android:background="@android:color/white"

android:orientation="vertical">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="@drawable/item_bg_select"

android:clickable="true"

android:gravity="center_vertical"

android:orientation="horizontal"

android:paddingLeft="20dp"

android:paddingRight="20dp">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/agg" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="15dp"

android:text="@string/shopping"

android:textColor="@android:color/black"

android:textSize="16sp" />

android:layout_width="match_parent"

android:layout_height="0.5dp"

android:layout_marginLeft="10dp"

android:layout_marginRight="10dp"

android:background="@color/color_e0e0e0">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="@drawable/item_bg_select"

android:clickable="true"

android:gravity="center_vertical"

android:orientation="horizontal"

android:paddingLeft="20dp"

android:paddingRight="20dp">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/ak6" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="15dp"

android:text="@string/games"

android:textColor="@android:color/black"

android:textSize="16sp" />

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="@android:color/white"

android:orientation="horizontal">

android:layout_width="0dp"

android:layout_height="wrap_content"

android:layout_weight="1"

android:drawableTop="@drawable/ala"

android:gravity="center"

android:text="@string/weixin"

android:textColor="@color/color_9e9e9e" />

android:layout_width="0dp"

android:layout_height="wrap_content"

android:layout_weight="1"

android:drawableTop="@drawable/al9"

android:gravity="center"

android:text="@string/countans"

android:textColor="@color/color_9e9e9e" />

android:layout_width="0dp"

android:layout_height="wrap_content"

android:layout_weight="1"

android:drawableTop="@drawable/alc"

android:gravity="center"

android:text="@string/finds"

android:textColor="@color/color_9e9e9e" />

android:layout_width="0dp"

android:layout_height="wrap_content"

android:layout_weight="1"

android:drawableTop="@drawable/ale"

android:gravity="center"

android:text="@string/me"

android:textColor="@color/color_9e9e9e" />

以上布局的效果图如下:

是不是差不多实现了微信一样的效果?那么我们怎么来判断以上布局是不是最优的呢?当然,我们是有工具来查看的。相信很多童鞋用过了,第一个就是 Hierarchy View,第二个就是 显示GPU过度绘制。

Hierarchy View检测布局嵌套层次

如果你是使用AS开发的话,你可以在 AS 工具栏中点击 Tools–>Android–>Android Device Monitor–>Hierarchy View。(至于Hierarchy View怎么使用这里就不仔细介绍了)你可以通过这个工具来查看当前布局的层次结构,如下图的布局的层次结构就是上面微信的布局:

ContentFrameLayout接点之后就是我们上面XML代码的布局了,从上图可以看到,我们布局最多有 5 层,其实你从代码中也可以看到是 5 层,那么我们是否能减少以上的布局的嵌套层次呢?答案是肯定的,废话不多说,我们直接上一份我优化过的布局代码吧。

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@color/color_eeeeee"

tools:context=".MainActivity">

android:id="@+id/tv_one"

style="@style/textStyle"

android:layout_marginTop="20dp"

android:background="@drawable/item_bg_select"

android:drawableLeft="@drawable/afe"

android:text="@string/fiends" />

android:id="@+id/lv_two"

style="@style/LinerLayoutStyle"

android:layout_below="@+id/tv_one"

app:divider="@drawable/lines"

app:dividerPadding="10dp"

app:showDividers="middle">

style="@style/textStyle"

android:background="@drawable/item_bg_select"

android:drawableLeft="@drawable/afg"

android:text="@string/scan" />

style="@style/textStyle"

android:background="@drawable/item_bg_select"

android:drawableLeft="@drawable/afh"

android:text="@string/shake" />

android:id="@+id/lv_threed"

style="@style/LinerLayoutStyle"

android:layout_below="@+id/lv_two"

app:divider="@drawable/lines"

app:dividerPadding="10dp"

app:showDividers="middle">

style="@style/textStyle"

android:background="@drawable/item_bg_select"

android:drawableLeft="@drawable/afd"

android:text="@string/nearby" />

style="@style/textStyle"

android:background="@drawable/item_bg_select"

android:drawableLeft="@drawable/afb"

android:text="@string/float_bottle" />

style="@style/LinerLayoutStyle"

android:layout_below="@+id/lv_threed"

app:divider="@drawable/lines"

app:dividerPadding="10dp"

app:showDividers="middle">

style="@style/textStyle"

android:background="@drawable/item_bg_select"

android:drawableLeft="@drawable/agg"

android:text="@string/shopping" />

style="@style/textStyle"

android:background="@drawable/item_bg_select"

android:drawableLeft="@drawable/ak6"

android:text="@string/games" />

layout="@layout/bottom_layout"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_alignParentBottom="true" />

哇,代码量少了很多啊,代码也简洁了许多,让人看着就很舒服,那么我们到底进行了怎样的优化呢?从以下几点总结:

使用 style 主题来定义一个通用的属性,从而重复利用代码,减少代码量。上面代码使用了两个style,一个是textStyle 和 LinerLayoutStyle ,代码如下:

match_parent

wrap_content

16sp

@android:color/black

20dp

20dp

center_vertical

true

match_parent

wrap_content

20dp

@android:color/white

vertical

2.减少布局嵌套的层次,上面布局使用TextView可以设置四个方向图片来直接替代LinerLayout下包裹一个ImageView 和TextView。从而这里减少了一层嵌套布局,再次利用RelativeLayout相对布局又减少了一层桥套,提高了加载布局的效率。看图:

从图中看出,不仅减少了两层嵌套布局,而且组件数目也减少,从而减少布局绘制的时间,大大提高了布局加载效率。

3.使用 LinearLayoutCompat 组件来实现线性布局元素之间的分割线,从而减少了使用View来实现分割线效果。

4.使用 include 标签加载底部菜单栏布局,include 标签的目的是重复利用布局,来减少代码了。

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="@android:color/white"

android:orientation="horizontal">

android:layout_width="0dp"

android:layout_height="wrap_content"

android:layout_weight="1"

android:drawableTop="@drawable/ala"

android:gravity="center"

android:text="@string/weixin"

android:textColor="@color/color_9e9e9e"

/>

android:layout_width="0dp"

android:layout_height="wrap_content"

android:layout_weight="1"

android:drawableTop="@drawable/al9"

android:gravity="center"

android:text="@string/countans"

android:textColor="@color/color_9e9e9e" />

android:layout_width="0dp"

android:layout_height="wrap_content"

android:layout_weight="1"

android:drawableTop="@drawable/alc"

android:gravity="center"

android:text="@string/finds"

android:textColor="@color/color_9e9e9e" />

android:layout_width="0dp"

android:layout_height="wrap_content"

android:layout_weight="1"

android:drawableTop="@drawable/ale"

android:gravity="center"

android:text="@string/me"

android:textColor="@color/color_9e9e9e" />

5.使用merge减少布局嵌套层次。

使用merge的前提条件就是merge标签必须是当前xml布局的根标签,例如:

........

也就是merge标签必须是当前布局的父布局。一般merge标签和include结合使用来减少布局嵌套层次。例如有如下布局:两个Button,以上一下。

android:layout_width="match_parent"

android:layout_height="match_parent">

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/button1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="text1"/>

android:id="@+id/button2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_below="@+id/button1"

android:text="text2"/>

该布局层次如下:

由上图看出除了根布局,我们自己写的布局有三层,两层都是RelativeLayout。那么能否优化呢?

(1)首先我们可以利用include标签简化xml布局。结果变成如下:

android:layout_width="match_parent"

android:layout_height="match_parent">

代码很清爽有木有,一目了然。然后layout_item布局如下:

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/button1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="text1"/>

android:id="@+id/button2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_below="@+id/button1"

android:text="text2"/>

到此,其实布局的嵌套层次和上面一样没有任何改变。那么我们利用merge标签来试试看结果怎样?merge标签代码如下:

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/button1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="text1"/>

android:id="@+id/button2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_below="@+id/button1"

android:text="text2"/>

此处仅仅把RelativeLayout标签换成merge标签,效果却大有不同。

利用merge标签以后的布局层次如下:

很明显减少了一层RelativeLayout布局,从而优化了布局。

总结:当父布局和子布局的根布局是同一种布局时,可以利用merge标签来减少一层嵌套布局。比如:你父布局是LinerLayout,此时子布局也是LinerLayout,就可以考虑使用merge来减少布局嵌套层次。

显示GPU过度绘制

你可以在手机打开 设置—->开发者选项—->显示GPU过度绘制,这个开关的作用是按不同颜色值来显示布局的过度绘制,绘制的层次从最优到最差:蓝,绿,淡红,红。给出一张直观的形象图片来表示吧

图片从上到下代表不同层次的OverDraw,我们在布局时候,尽量减少红色 Overdraw,看到更多的蓝色区域。来看看微信的 Overdraw图和我们自定义的布局Overdraw图吧

第一张图是 腾讯微信的Overdraw 图,第二张图片是我们自定义的 Overdraw 图片。从上面两张图片看出,我们自己的布局和微信原版的布局 Overdraw 过度绘制情况差不多,没啥区别。那么我们能不能去减少红色部分的过度绘制呢?试试吧!

我们先去掉最顶端布局RelativeLayout的背景

android:background="@color/color_eeeeee"

然后修改每个item选择资源 selector

android:background="@drawable/item_bg_select1"

之前的 item_bg_select.xml 资源是如下代码:

修改之后的 item_bg_select1.xml资源代码如下:

我们发现,新的 selector资源去除了

因为整个背景是白色的,无需重复设置正常情况下item的背景颜色。

修改之后的效果图如下:

看出,基本没有红色区域,从而提高布局的绘制效率。

总结:现在看来,我们通过减少背景颜色的设置来减少Overdraw的情况。我们自己布局过度绘制的情况比微信本身的情况有很大的改善,是不是感觉很nice~~。

懒加载布局 ViewStub

除了以上两种方法来优化布局,还有其他办法来继续优化布局,在某些情况下,有些布局是仅在需要时才加载,比如小米手机的添加联系人功能就有在编辑姓名的时候有一个下拉按钮显示更多输入信息,看图

遇到这种情况,我们首先想到的 就是将不常用的元素使用INVISIBLE或者GONE进行隐藏,这样是否真的好呢?是否达到了 布局优化的最终效果呢?利用 INVISIBLE只是隐藏布局,但是布局还是占居当前位置,且系统在加载布局的时候这一部分还是会绘制出来,同样花费绘制时间。那么有没有好的办法来解决这一问题呢?不言而喻,我们可以使用懒加载布局 ViewStub。

ViewStub是Android为此提供了一种非常轻量级的控件。ViewStub虽说也是View的一种,但是它没有大小,没有绘制功能,也不参与布局,资源消耗非常低,将它放置在布局当中基本可以认为是完全不会影响性能的。

下面我们来学习一下 ViewStub的使用方法吧!

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

android:padding="20dp">

android:id="@+id/et_name"

android:layout_width="150dp"

android:drawableRight="@drawable/a0e"

android:layout_height="wrap_content"

android:hint="@string/name" />

android:id="@+id/view_stub"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout="@layout/item_name" />

android:layout_width="150dp"

android:layout_height="wrap_content"

android:hint="@string/comp" />

android:layout_width="150dp"

android:layout_height="wrap_content"

android:hint="@string/lead" />

item_name.xml 布局如下:

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:id="@+id/et_name1"

android:layout_width="150dp"

android:layout_height="wrap_content"

android:hint="@string/name1" />

android:id="@+id/et_name2"

android:layout_width="150dp"

android:layout_height="wrap_content"

android:hint="@string/name2" />

android:id="@+id/et_name3"

android:layout_width="150dp"

android:layout_height="wrap_content"

android:hint="@string/name3" />

android:id="@+id/et_name4"

android:layout_width="150dp"

android:layout_height="wrap_content"

android:hint="@string/name4" />

然后你在代码中这么使用即可

findViewById(R.id.et_name).setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

ViewStub viewStub = (ViewStub) findViewById(R.id.view_stub);

if (null != viewStub) {

//主要是这一句显示更多布局

View view = viewStub.inflate();

EditText name1 = (EditText) view.findViewById(R.id.et_name1);

EditText name2 = (EditText) view.findViewById(R.id.et_name2);

EditText name3 = (EditText) view.findViewById(R.id.et_name3);

EditText name4 = (EditText) view.findViewById(R.id.et_name4);

}

}

});

效果图如下:

从效果图可以看出,当用户点击姓名下拉按钮时,其他关于姓名的布局就加载出来了,而且原来的布局是显示在ViewStub布局之下的,位置显示没有任何异常。当然你可以通过 setVisibility(View.VISIBLE)或者viewStub.inflate()方来来让其显示,通过setVisibility(View.INVISIBLE)来隐藏 ViewStub。

Android Lint 工具

这里不展开介绍 Lint 工具,感兴趣的童鞋可以自己网上搜索一把,这个工具主要是用来检查工程中代码的不合理,布局不合理,资源重复,图片重复,等,让开发者进一步优化自己的应用。如果你是AS 用户,你可以在工具栏 Analyze—>Inspect Code 打开此工具使用。

android布局优化 工具,详解Android布局优化相关推荐

  1. android常用技术网站收藏过的网址 给 Android 开发者的 RxJava 详解 Android设备标识-没有完美的解决方案-只有取舍 - 小彼得的专栏 - 博客频道 - CSDN.NET

    收藏过的网址 http://www.jianshu.com/p/a7b36d682b6f?ref=myread  Android插件化快速入门与实例解析 http://www.cnblogs.com/ ...

  2. android:stretchcolumns=quot;*quot;,详解Android TableLayout中stretchColumns、shrinkColumns的用法...

    详解Android 中TableLayout中stretchColumns.shrinkColumns的用法 android:stretchColumns="1" android: ...

  3. android uri图片压缩,详解android 通过uri获取bitmap图片并压缩

    详解android 通过uri获取bitmap图片并压缩 很多人在调用图库选择图片时会在onactivityresult中用media.getbitmap来获取返回的图片,如下: uri mimage ...

  4. android led闪烁功能,详解Android应用层制作LED指示灯

    详解Android应用层制作LED指示灯 在Java应用层修改LED指示灯的颜色,这个花了我半天时间, 才实现该功能! public class LEDActivity extends Activit ...

  5. android任务 进程 线程详解,Android任务、进程、线程详解

    singleTop模式,基本上于standard分歧,仅正在请求的Activity反好位于栈顶时,无所区别.此时,配放成singleTop的Activity,不再会构制新的实例加入到Task栈外,而是 ...

  6. Android编程之SparseArrayE详解 Android编程之SparseArrayE详解

    Android编程之SparseArray<E>详解 分类:Android2012-09-01 13:139412人阅读评论(5)收藏举报 android编程delete存储list 最近 ...

  7. tuned-adm性能优化工具详解

    详解1 tuned-adm 是一个命令行工具,提供一些不同配置文件以提高一些特定用例性能 tuned-adm工具使用方法 tuned-adm list                        # ...

  8. android include 控件详解,Android开发中include控件用法分析

    本文实例讲述了Android开发中include控件用法.分享给大家供大家参考,具体如下: 我们知道,基于Android系统的应用程序的开发,界面设计是非常重要的,它关系着用户体验的好坏.一个好的界面 ...

  9. 简诉android源代码编译过程,详解Android源码的编译

    在这里我们将介绍的是Android源码的编译,主要基于Android 1.0环境下.希望对大家有所帮助. 本文将为大家介绍的是如何设置Android源码的编译环境,包括Linux下的配置.主要基于An ...

最新文章

  1. 计算机网络是啥意思啊,no signal是什么意思啊
  2. Csharp关键字----delegate(委托)
  3. 黑星什么意思_星月菩提黑星海南料什么意思
  4. Hadoop教程(三):HDFS、MapReduce、程序入门实践
  5. 几种常见的Web攻击
  6. 机器学习(三十二)——t-SNE, Adaboost
  7. webgis 行政图报错_WebGIS 地图 示例源码下载
  8. linux7yum安装mysql,CentOS7 使用yum安装mysql
  9. USACO-Section1.3 Milking Cows (区间问题)
  10. zookeeper中展示所有节点_zookeeper工作原理与节点使用
  11. 关于DevEco Studio踩过的各种坑~
  12. CONTINUAL LEARNING FOR AUTOMATED AUDIO CAPTIONING USING THE LEARNING WITHOUT FORGETTING APPROACH
  13. 软件工程师是青春饭吗?
  14. 我的2016—遇见自己,遇见未来
  15. 算法小记(1)--判断三个数的最大,最小
  16. 2019智能手表推荐_智能手表哪款好?2020智能手表推荐
  17. 专访民生银行:CPOS平台如何从线下布局移动支付
  18. 园艺智慧_园艺日:如何在完全远程的情况下运行技术债务清理日
  19. eaxsinbx_研究性教学在分部积分法教学中的应用
  20. qq怎么设置android在线,安卓手机QQ在线怎么更改显示为苹果手机QQ在线

热门文章

  1. 准备刺第一针了(飞秋官方下载)
  2. 它有许多功能的局域网
  3. 联信高效的数据传输机制
  4. SOCKET入门最简单的程序啊
  5. 原创]Windows Gdi入门初级应用(VC SDK)
  6. 三十五岁后,如何自学WEB前端编程
  7. dp聚类算法_【深度】基于残差分析的混合属性数据聚类算法
  8. 带你走进和声搜索算法(Harmony search )的世界!
  9. 聊聊用于特征处理的tsfresh
  10. 基因功能不确定?做一下单基因GSEA怎么样?