风流不在谈锋胜,袖手无言味最长。这篇文章主要讲述Android布局优化相关的知识,希望能为你提供帮助。
#前言#
本篇文章为android优化的布局部分,该部分应该是Android中很重要的,无论是在自定义控件中,还是在简单的书写布局时,都应该尽量遵循一些优化原则,这样布局的绘制效率才会更高,体验才能更好。
#一 优化layout的层级#
Layout结构如果太复杂,Android的绘制过程就会很复杂,measure过程就会很复杂,我分析的View绘制机制中详细介绍了整个测量、布局和绘制过程,过于复杂、嵌套的布局会造成性能问题。
1.1 避免嵌套嵌套的 LinearLayout 可能会使得 View 的层级结构很深。使用LinearLayout时,通常我们喜欢用嵌套的布局来动态设置一个View的Visibility ,由于LinearLayout是线性的,因此即使隐藏一个View也不会影响到其它View的排列。而在RelativeLayout中,View的位置都是相对于其它View的,因此,隐藏之后,会导致之前的View没有参考对象了,导致的相对位置改变,这时你可以使用alignWithParentIfMissing=”true”来处理这种情况。
此外,嵌套使用了 layout_weight 参数的 LinearLayout 的计算量会尤其大,因为每个子元素都需要被测量两次。这对需要多次重复 inflate 的 Layout 尤其需要注意,比如使用 ListView 或 GridView 时。
1.2 使用merge标签优化层级在使用了include后可能导致布局嵌套过多,出现不必要的layout节点,从而导致解析变慢。
merge标签可用于两种典型情况:
- 布局顶结点是FrameLayout且不需要设置background或padding等属性,可以用merge代替,因为Activity内容试图的parent view就是个FrameLayout,所以可以用merge消除只剩一个。
- 某布局作为子布局被其他布局include时,使用merge当作该布局的顶节点,这样在被引入时顶结点会自动被忽略,而将其子节点全部合并到主布局中。
为了避免这种情况,你可以用元素来替代可重用 Layout 的根节点。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 | < merge xmlns:android="http://schemas.android.com/apk/res/android"> < Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/add"/> < Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/delete"/> < /merge> |
#二 使用标签重用Layout#
如果你的程序 UI 在不同地方重复使用某个 Layout,那本节教你如何创建高效的,可重用的 Layout 部件,并把它们“包含”到 UI Layout 中。
为了高效重用整个的 Layout,你可以使用和标签把其他 Layout 嵌入当前 Layout。
三 按需载入视图除了简单的把一个 Layout 包含到另一个中,你可能还想在程序开始后,仅当你的 Layout 对用户可见时才开始载入。
3.1 不需要立即加载的布局,设置为GONE,系统会跳过,不加载 3.2 使用ViewStub 实现按需加载ViewStub 是一个轻量的视图,不需要大小信息,也不会在被加入的 Layout 中绘制任何东西。每个 ViewStub 只需要设置 android:layout 属性来指定需要被 inflate 的 Layout 类型。viewstub常用来引入那些默认不会显示,只在特殊情况下显示的布局,如进度布局、网络失败显示的刷新布局、信息出错出现的提示布局等。
以下 ViewStub 是一个半透明的进度条覆盖层。功能上讲,它应该只在新的数据项被导入到应用程序时可见。
1 2 3 4 5 6 7 | < ViewStub android:id="@+id/stub_import" android:inflatedId="@+id/panel_import" android:layout="@layout/progress_overlay" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" /> |
当你要载入用 ViewStub 声明的 Layout 时,要么用 setVisibility(View.VISIBLE) 设置它的可见性,要么调用其 inflate() 方法。
下面以在一个布局main.xml中加入网络错误时的提示页面network_error.xml为例。main.mxl代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | < ?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" > …… < ViewStub android:id="@+id/network_error_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout="@layout/network_error" /> < /RelativeLayout> |
setVisibility(View.VISIBLE)方式
1 2 3 | View viewStub = ((ViewStub)findViewById(R.id.stub_import)); viewStub.setVisibility(View.VISIBLE); netErrorLayout = findViewById(R.id.net_error_layout)) |
1 | View netErrorLayout = ((ViewStub) findViewById(R.id.net_error_layout)).inflate(); |
inflate() 方法会在渲染完成后返回给被 inflate 的视图,所以你不需要再调用 findViewById() 去查找这个元素。减少inflate的次数,也会对效率有一点提升。
而setVisible方式还需要再次findViewById找到ViewStub中的元素。
一旦 ViewStub 可见或是被 inflate 了,ViewStub 元素就不存在了。取而代之的是被 inflate 的 Layout,其 id 是 ViewStub 上的 android:inflatedId 属性。(ViewStub 的 android:id 属性仅在 ViewStub 可见以前可用)
注意:ViewStub 的一个缺陷是,它目前不支持使用标签的 Layout
#四 ListView的优化#
如果你有一个包含复杂或者每个项 (item) 包含很多数据的 ListView ,那么上下滚动的性能可能会降低。本节给你一些关于如何把滚动变得更流畅的提示。
保持程序流畅的关键,是让主线程(UI 线程)不要进行大量运算。你要确保在其他线程执行磁盘读写、网络读写或是 SQL 操作等。为了测试你的应用的状态,你可以启用 StrictMode。
##4.1 使用后台线程##
你应该把主线程中的耗时间的操作,提取到一个后台线程中,使得主线程只关注 UI 绘画。
##4.2 在 View Holder 中填入视图对象##
使用convertView、
你的代码可能在 ListView 滑动时经常使用 findViewById(),这样会降低性能。即使是 Adapter 返回一个用于回收的 convertView,你仍然需要查找这个元素并更新它。避免频繁调用 findViewById() 的方法之一,就是使用 View Holder(视图占位符)设计模式。
ViewHolder 存储了标签下的每个视图。这样你不用频繁查找这个元素:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | static class ViewHolder { TextView text; TextView timestamp; ImageView icon; ProgressBar progress; int position; } ``` 然后,在 Layout 的类中生成一个 ViewHolder 对象: ```java ViewHolder holder = new ViewHolder(); holder.icon = (ImageView) convertView.findViewById(R.id.listitem_image); ... convertView.setTag(holder); |
##4.3 getView不要做复杂的操作##
因为每一条Item移入屏幕的时候,都会调用getView,不要在getView中做复杂的操作,不要频繁的创建对象。Item点击的处理不要提前做。特别是在快速滑动的时候,会导致频繁的调用getView。
#五 优化提示#
尽量使用RelativeLayout,可以减少层级的嵌套。
慎用LinearLayout的layout_weight属性,可以使用RelativeLayout的centerHorizontal=”true”、toLeft、toRight代替
【Android布局优化】#六 书写规范上的优化#
##6.1 Id的命名##
为了便于识别,你可以根据自己的业务来对当前界面的资源进行命名,比如当前是登陆界面,那么你可以这样命名:
login_edit_username
login_edit_password
login_btn_submit
login_txv_forgot_pass
##6.2 资源的命名##
ic_action_add, ic_action_location (ActionBar Icons)
ic_play, ic_save (General Icons)
ic_tab_music, ic_tab_more (Tab Icons)
##6.3 通用的资源命名##
对style.xml和dimens.xml的命名可以通用的尽量通用,因为一个项目的基本视图很多都是通用的,比如ActionBar、ListView等,规范通用的命名可以很方便的移植到其它项目中。
1 2 3 4 5 6 7 8 9 10 11 12 | < color name="list_item_large"> #FCA558< /color> < color name="list_item_small"> #FBA228< /color> < dimen name="list_item_large"> 24dp< /dimen> < dimen name="list_item_small"> 18dp< /dimen> < !-- 简单ListView样式 --> < style name="list_view_style_default"> < item name="android:layout_width"> fill_parent< /item> < item name="android:layout_height"> wrap_content< /item> ... < /style> |
推荐阅读
- 防火应用锁定 Firewall App Blocker v1.6 绿色便携版
- Android圆角Tag控件的另类实现
- 5款最佳轻量级浏览器合集(哪个最适合你())
- 5个最好用的HTML 5编辑器合集(你最喜欢哪个())
- 5款最佳DVD制作软件合集(哪个最实用())
- 服务器和工作站的最佳补丁管理软件(哪个最好())
- 5个最好的免费垃圾邮件过滤器(哪个最适合你())
- 5个最佳日志管理和分析合集(Splunk替代方案)
- 5个最佳连接路径分析工具合集(Traceroute替代方案)