Android开发——布局性能优化的一些技巧(一)
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开发——布局性能优化的一些技巧(一)的更多相关文章
- Android开发——布局性能优化的一些技巧(二)
, 0, drawable.getMinimumWidth(),dra.getMinimumHeight()); tv.setCompoundDrawables(null, null, drawabl ...
- 李洪强iOS开发之性能优化技巧
李洪强iOS开发之性能优化技巧 通过静态 Analyze 工具,以及运行时 Profile 工具分析性能瓶颈,并进行性能优化.结合本人在开发中遇到的问题,可以从以下几个方面进行性能优化. 一.view ...
- <只看这个就够了。。。>Android自动化测试及性能优化
Android自动化测试及性能优化 分类: Android Java Tools2012-12-09 23:31 4300人阅读 评论(0) 收藏 举报 软件自动化测试对于程序员来说能够确保软件开发的 ...
- C#性能优化的一些技巧
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:C#性能优化的一些技巧.
- ym——Android之ListView性能优化
转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! Android之ListView性能优化 假设有看过我写过的15k面试题的朋友们一定知 ...
- android开发中图片优化步骤
android开发中图片优化方法 1.图片加载方法,方便用户加载图片 /*** * 加载本地图片 * @param context:主运行函数实例 * @param bitAdress:图片地址,一般 ...
- 分享10条PHP性能优化的小技巧,帮助你更好的用PHP开发:
1. foreach效率更高,尽量用foreach代替while和for循环. 2. 循环内部不要声明变量,尤其是对象这样的变量. 3. 在多重嵌套循环中,如有可能,应当将最长的循环放在内层,最短循环 ...
- 那些Android中的性能优化
性能优化是一个大的范畴,如果有人问你在Android中如何做性能优化的,也许都不知道从哪开始说起. 首先要明白的是,为什么我们的App需要优化,最显而易见的时刻:用户say,什么狗屎,刷这么久都没反应 ...
- Android应用程序性能优化Tips
对于我们设计的应用需要做到以下特征:build an app that's smooth, responsive(反应敏捷), and uses as little battery as possib ...
随机推荐
- vue-cli的webpack模板项目配置文件说明
如果没有vue-cli,那么进行vue项目的开发环境配置将是很费力的一件事情,现在脚手架可以快速构建一个开发环境,是很不错的.不过对于脚手架构建的配置,还是要大概了解一下,方便自己调试配置. 初始化一 ...
- SQL Server 登录名、用户、角色与权限
1.在SQL Server中,用户和角色是分为服务器级别和数据库级别的 2.服务器级别 登录名:指有权限登录到某服务器的用户,例如超级管理员的登录名是sa: 登录名具体位置在 数据库——>安全 ...
- linux something
使用的UbuntuKylin source error e1:apt-get update提示没有证书 e2:访问不了阿里云源服务器 e3:GPG 错误:http://download.mono-p ...
- 编写带有点击特效的UIButton
编写带有点击特效的UIButton 效果: 源码: // // ViewController.m // Button // // Created by XianMingYou on 15/1/18. ...
- 使用CoreData [3]
使用CoreData [3] 此篇幅介绍CoreData如何升级版本防止崩溃 把你之前创建的实体文件全部删除掉,把沙盒中的数据库文件删除掉,实体只保持一个,然后重新创建出实体文件. - (BOOL)a ...
- Office 365 Pass-through身份验证及Seamless Single Sign-On
Hello 小伙伴们, 这篇文章将视点聚焦在传递身份验证(Pass-through Authentication)上,将分享如何安装,配置和测试Azure Active Directory(Azure ...
- javascript Spline代码
代码是通过网上一个winform代码中提取修改而来的.后转为javascript 版本. /* points = new Array(); points.push({x:1,y:2}); */ fun ...
- 你的ABAP程序给佛祖开过光么?来试试Jerry这个小技巧
最近Jerry在忙一个项目,技术栈换成了nodejs平台,语言换成了JavaScript,因为赶项目进度,一直没时间更新公众号.感谢大家的支持,关注人数还是慢慢地增长到了3000. 今天我们来聊聊一个 ...
- P2245 星际导航
题目描述 sideman 做好了回到 Gliese星球的硬件准备,但是 sideman 的导航系统还没有完全设计好.为了方便起见,我们可以认为宇宙是一张有 N 个顶点和 M 条边的带权无向图,顶点表示 ...
- Kubernetes 初探
一.容器: 1. 容器是运行一个或一组进程的方法,使得这些进程和主机上其他进程相隔离 2. 容器类似于虚拟机,但不同于虚拟机 容器 ...