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. leetcode题解之Find the Duplicate Number

    1.题目描述 2.分析 利用C++的 标准模板库 set 对数组进行读取,然后插入,如果检测到元素已经在set内部,则返回该元素值即可.时间复杂度为 O(n),空间复杂度为 O(n); 3.代码 in ...

  2. 5.FileWriter 和 BufferWriter

    FileWriter 和 BufferWriter的使用场景  IO这块,各种Writer,Reader,让人眼晕 而在网上基本找不到在什么时候用哪个类,并且网上的IO demo 很多用法都是错的 在 ...

  3. Oracle EBS 清除并发请求和(或)管理器数据 请求

    请求说明:该请求可以清除平时提交的请求日志文件.并发管理器的日志文件.报表输出文件.并发请求和并发管理器进程的历史记录信息. 参数说明:(红色标注字段为必输项)1.  实体:ALL:清除请求历史记录. ...

  4. 查看windows所有exe的启动参数。

    在cmd中输入 wmicprocess 即可查看到所有进程的启动参数和运行参数.

  5. 4 个用于构建优秀的命令行用户界面的 Python 库

    作者: Amjith Ramanujam 译者: LCTT Lv Feng 在这个分为两篇的关于具有绝佳命令行界面的终端程序的系列文章的第二篇教程中,我们将讨论 Prompt.Toolkit.Clic ...

  6. DES加密(支持ARC与MRC)

    DES加密(支持ARC与MRC) 源文件: YXCrypto.h 与 YXCrypto.m // // YXCrypto.h // 用秘钥给字符串加密或者解密 // // Created by You ...

  7. Linux stat命令详解

    stat:查看文件或者文件系统的状态  -->可以查看时间等属性 stat常见命令参数 Usage: stat [OPTION]... FILE... Display file or file ...

  8. UI(二)之正式过程

    2018-12-04 09:48:25 1.SetWindowsHookEx ·钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统.每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获 ...

  9. codeforces 424D Biathlon Track

    codeforces 424D Biathlon Track 题意 题解 代码 #include<bits/stdc++.h> using namespace std; #define f ...

  10. Istio 1.1尝鲜记

    近几天Istio1.1的发布引起了技术界巨大的反响,为了让更多技术爱好者能够亲自体验Istio1.1,公司的技术大佬赶出了这篇尝鲜教程,其中包括环境.安装.可能遇到的问题及解决方式等,希望对大家有所帮 ...