0. 前言

上一篇我们分析了为什么LinearLayout会比RelativeLayout性能更高,意义在于分析了这两种布局的实现源码,算是对一个小结论的证明过程,但是对布局性能的优化效果,对这两种布局的选择远不如减少布局层级、避免过分绘制、按需加载等效果明显。所以本篇将着重总结Android布局性能优化的各种技巧。本文原创,转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52923827

 

1.   <include/>

<include>标签可以在一个布局中引入另外一个布局,通常适合于界面布局复杂、不同界面有共用布局的APP中,比如顶部布局、侧边栏布局、底部Tab栏布局、ListView的item布局等,将这些公共布局抽取出来再通过<include>标签引用,既可以使代码结构清晰,又可统一修改使用。

比如先写一个公共的标题栏标题栏title_bar.xml(这里就不具体实现了),并在我们的主xml文件里调用<include>来使用这个公共布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/title_bar"/>
</RelativeLayout>

当然include也可以使用layout属性来设置布局文件的宽高和位置,但需要注意的是,必须要复写android:layout_width和android:layout_height属性才能使用其它属性(如:android:layout_grivity、android:layout_align...、android:id等),这样可以避免include引用中的子组件属性影响到include的布局效果。

比如下面这个例子给我们include进的组件设置高度和位置:

<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">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp">
<include layout="@layout/title_bar" />
<include
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
layout="@layout/ title_bar"/>
</RelativeLayout>
</RelativeLayout>

2.   减少嵌套

这个问题我们在LinearLayout和RelativeLayout的性能对对比中已经解释过了,在不响应层级深度的情况下,使用Linearlayout而不是RelativeLayout。为开发者默认新建RelativeLayout是希望开发者能采用尽量少的View层级,因为很多效果是需要多层LinearLayout的嵌套,这必然不如一层的RelativeLayout性能更好。为了确保文章的实时更新,实时修改可能出错的地方,请确保这篇是原文,而不是无脑转载来的“原创文”,原文链接为SEU_Calvin的博客

3.  <merge/>

<merge/>标签通过减少View树的层级来优化Android的布局。先来用个例子演示一下:

<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" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="merge标签使用" />
</RelativeLayout>

运行后使用“DDMS -> DumpView Hierarchy for UI Automator”工具,截图如下:

最下面两层RelativeLayout与TextView就是布局中的内容,上面的FrameLayout是ActivitysetContentView添加的顶层视图。下面我们将上述布局代码中的RelativeLayout修改为merge标签再查看层级结构如下:

(1)从结果来看,FrameLayout下面直接就是TextView,与之前的相比少了一层RelativeLayout但效果相同。这个例子中TextView不需要指定任何针对父视图的布局属性,只用于添加到父视图上并显示,这种情况就可以使用<merge/>标签优化。但是我们一般很少遇到这种情况。为了确保文章的实时更新,实时修改可能出错的地方,请确保这篇是原文,而不是无脑转载来的“原创文”,原文链接为SEU_Calvin的博客

(2)更多的<merge/>标签使用情景是在LinearLayout里面嵌入一个布局(比如使用了include),而恰恰这个布局的根节点也是LinearLayout,这样就多了一层没有用的嵌套,增加了View深度,这个时候如果我们使用merge根标签就修饰被嵌入的布局的根标签就可以避免此问题。

4.   ViewStub

一个最最最可能使用到的场景就是请求网络加载列表,如果网络异常或者加载失败,我们可以显示一个用于提示用户的View,上面可以点击重新加载。当网络正常时,我们就没有理由显示这个提示View。但是如果我们通过代码逻辑这种方式实现动态更改这个View的可见性(GONE或者VISIBLE),在Inflate布局的时候View仍然会被Inflate,也就是说仍然会创建对象,会被实例化且耗费内存资源。

为了解决这个性能问题,ViewStub应运而生,ViewStub是一个轻量级的View,看不见、不占布局位置、占用资源非常小。当ViewStub被设置为可见或调用了ViewStub.inflate()的时候,ViewStub所指向的布局才会被Inflate和实例化,然后ViewStub的布局属性都会传给它所指向的布局,ViewStub控件本身就不存在了(ViewStub对象会被置空),取而代之的是被inflate的Layout,因此它也被称做惰性控件。为了确保文章的实时更新,实时修改可能出错的地方,请确保这篇是原文,而不是无脑转载来的“原创文”,原文链接为SEU_Calvin的博客

综上ViewStub的原理,就可以使用它来方便的在运行时,决定要不要显示某个布局。使用实例如下:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
……
<ViewStub
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/hint_fail_view"
android:inflatedId="@+id/hint_fail_view"
android:layout="@layout/fail_view"/>
</merge>

android:layout="@layout/fail_view"指向页面加载失败的布局文件,里面包含一个id为tv的TextView。

当出现网络异常时,我们在代码里这样使用ViewStub:

private View hintFailView;
if (网络异常) {
if (hintFailView == null) {
ViewStub viewStub = (ViewStub)this.findViewById(R.id.hint_fail_view);
hintFailView = viewStub.inflate(); //注意这里
TextView textView = (TextView) hintFailView.findViewById(R.id.tv);
textView.setText("网络异常");
}
hintFailView.setVisibility(View.VISIBLE);
}else{
//网络正常
if (hintFailView!= null) {
hintFailView.setVisibility(View.GONE);
}
//业务逻辑
}

5.  避免OverDraw

一个简单的过度绘制例子是父控件和其上的子控件都设置了Background,那么人们是看不到被子控件所覆盖的那部分父控件背景的,这就造成了OverDraw,我们可以通过设置-开发者选项-显示GPU过度绘制来查看应用是否存在严重的OverDraw问题。

如果你发现应用中有些色块为红色,那么你可要去优化它了,你需要去根据颜色提示去找到你过度绘制的地方,需要注意的是在我们有自己的背景色的情况下,顶层View的背景色我们可以置空来优化。

setContentView(R.layout.activity_overdraw_01);
getWindow().setBackgroundDrawable(null);

除了去除不必要的背景色,还有一个防止OverDraw的方法,那就是使用画布的clipRect()方法来去除自定义View中不必要的重叠绘制。
在看clipRect方法之前先看看如果将res目录下的图片文件转换为bitmap对象,这里总结了两种方法,大家可以参考使用:

InputStream is = this.getContext().getResources().openRawResource(R.drawable.icon);
Bitmap mBitmap = BitmapFactory.decodeStream(is);
//或者使用BitmapDrawable
Bitmap mBitmap = new BitmapDrawable(is).getBitmap();

clipRect方法可以截取画布中的一个矩形区域,在此区域外的将不再绘制显示。实例如下:

/*
*author SEU_Calvin in 2016/10
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = mBmp.getWidth();
int height = mBmp.getHeight(); canvas.save();
mPaint.setColor(Color.CYAN);
//先在屏幕的0,0处绘制一个与我们Bitmap宽高相等的蓝色矩形
canvas.drawRect(0, 0, width, height, mPaint);
canvas.restore(); canvas.save();
//裁剪画布,左上角为0,0 右下角为指定宽高的2倍和1.5倍
canvas.clipRect(0, 0, width*2, height*3/2);
//以width,height为左上角绘制我们的Bitmap,由于图片的下半部分在裁剪画布之外所以不显示
canvas.drawBitmap(mBmp, width, height, mPaint);
canvas.restore();
}

结果如下所示,工作过程已经在代码的注释里写的很清楚了。

6.  其他小技巧

为了控制篇幅,将一些看了让人感到惊艳的布局优化小技巧总结分享到了布局性能优化的一些技巧(二),希望可以帮助到你~

最后希望各位看官老爷们多点赞支持~

Android开发——布局性能优化的一些技巧(一)的更多相关文章

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

    , 0, drawable.getMinimumWidth(),dra.getMinimumHeight()); tv.setCompoundDrawables(null, null, drawabl ...

  2. 李洪强iOS开发之性能优化技巧

    李洪强iOS开发之性能优化技巧 通过静态 Analyze 工具,以及运行时 Profile 工具分析性能瓶颈,并进行性能优化.结合本人在开发中遇到的问题,可以从以下几个方面进行性能优化. 一.view ...

  3. <只看这个就够了。。。>Android自动化测试及性能优化

    Android自动化测试及性能优化 分类: Android Java Tools2012-12-09 23:31 4300人阅读 评论(0) 收藏 举报 软件自动化测试对于程序员来说能够确保软件开发的 ...

  4. C#性能优化的一些技巧

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:C#性能优化的一些技巧.

  5. ym——Android之ListView性能优化

    转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! Android之ListView性能优化 假设有看过我写过的15k面试题的朋友们一定知 ...

  6. android开发中图片优化步骤

    android开发中图片优化方法 1.图片加载方法,方便用户加载图片 /*** * 加载本地图片 * @param context:主运行函数实例 * @param bitAdress:图片地址,一般 ...

  7. 分享10条PHP性能优化的小技巧,帮助你更好的用PHP开发:

    1. foreach效率更高,尽量用foreach代替while和for循环. 2. 循环内部不要声明变量,尤其是对象这样的变量. 3. 在多重嵌套循环中,如有可能,应当将最长的循环放在内层,最短循环 ...

  8. 那些Android中的性能优化

    性能优化是一个大的范畴,如果有人问你在Android中如何做性能优化的,也许都不知道从哪开始说起. 首先要明白的是,为什么我们的App需要优化,最显而易见的时刻:用户say,什么狗屎,刷这么久都没反应 ...

  9. Android应用程序性能优化Tips

    对于我们设计的应用需要做到以下特征:build an app that's smooth, responsive(反应敏捷), and uses as little battery as possib ...

随机推荐

  1. 3D打印材料的发展现状(1)

    材料是3D打印的物质基础,也是当前制约3D打印发展的瓶颈. 3D打印材料 3D打印材料是3D打印技术发展的重要物质基础,材料的发展对于3D打印的发展有重要的作用. 目前,3D打印材料主要包括工程塑料. ...

  2. ExpressRoute 合作伙伴和对等位置

    本文中的表格提供有关 ExpressRoute 连接提供商.ExpressRoute 地理覆盖范围.通过 ExpressRoute 支持的 Azure 服务以及 ExpressRoute 系统集成商 ...

  3. Azure 镜像市场发布商指南

    Azure 镜像市场发布商指南 本指南提供独立软件供应商产品上架到 Azure 镜像市场(以下简称 Azure 镜像市场)需要遵循的全流程. 文档适用范围 本指南适用于希望通过由世纪互联运营的Micr ...

  4. hyper-v 无线网连接

    本人的工作环境 笔记本一台,window 10系统64位.平时连接的是有线网,今天回到家里,准备继续在Hyper-v虚拟机上进行操作,发现不能连网,自己立马想到了是不是没有虚拟机上没有和主机共享无线网 ...

  5. [翻译] AnchoredFloatView

    AnchoredFloatView Float View over TableView to indicate selected row direction Float View 可以用来指示 Tab ...

  6. word 排版用到双直线、波浪线、虚线 、直线、隔行线等技巧

    在办公或毕业设计时,有时排版需要插入双直线.波浪线.虚线 .直线.隔行线等而烦恼, 今天小白与大家分享技巧如下: 感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮.本文欢迎各位转载,但 ...

  7. zabbix图形插件:Graphtree

    目的:为了达图形聚合 参考博文:https://blog.csdn.net/mysunshineto/article/details/80242754 Graphtree由OneOaaS开发并开源出来 ...

  8. November 15th 2016 Week 47th Tuesday

    Success is finding satisfaction in giving a little more than you take. 成功就是付出比得到多,仍然心满意足. Can I find ...

  9. Spring Boot REST

    资源(Resources) 所谓资源,就是网络上一个实体,或者是网络上一个具体信息.他可以是一段文本,一张图片,一种服务,总之是一个具体的实体.可以用一个URI(统一资源定位符)指向它,每种资源对应一 ...

  10. 个人作业——APP案例分析

    APP--饿了么:平台--Android 第一部分 调研, 评测 1 个人上手体验 首先送上APP截图一张: 相信很多学生都用过这个APP了,第一次使用都是因为新用户有大额的满减优惠才下载这个APP使 ...