有一句古话:不论黑猫白猫,能抓到耗子就是好猫。这个也许在某些方面是有道理的,但对于我们追求精益求精的思想是背道而驰的,往往就是因为满足于一个结果,而放弃探求更加优化的处理方法。
当关注应用程序或者游戏所达到的结果时,往往非常容易忽视一些优化的问题,例如内存优化,线程优化,Media优化和UI优化等等。不同的模块都存 在更为巧妙的方式来对待一般性问题,所以每当我们实现一个行为后,稍微多花一些时间来考虑目前所作的工作是否存在更为高效的解决办法。
这一次我们对常用的UI Layout优化说起,这个例子转载于 android developing blog
在Android中最常用LinearLayout 表示UI的框架,而且也是最直观和方便的方法。例如创建一个UI用于展现Item的基本内容。如图所示:
线框图:
直接可以通过LinearLayout快速的实现这个UI的排列:
<LinearLayout xmlns: |
尽管可以通过Linearlayout实现我们所预想的结果,但是在这里存在一个优化的问题,尤其是针对为大量Items。比较RelativeLayout和LinearLayout,在资源利用上前者会占用更少的资源而达到相同的效果,以下是用RelativeLayout 实现的代码:
<RelativeLayout xmlns:android ="http://schemas.android.com/apk/res/android" |
针对RelativeLayout有一点需要注意,因为它内部是通过多个View之间的关系而确定的框架,那么当其中某一个View因为某些需要调用GONE 来完全隐藏掉后,会影响与其相关联的Views。Android为我们提供了一个属性 alignWithParentIfMissing 用于解决类似问题,当某一个View无法找到与其相关联的Views后将依据alignWithParentIfMissing 的设定判断是否与父级View对齐。
下边是两种不同layout在Hierarchy Viewer中的层级关系图:
简单或复杂的问题都需要时常考虑如何优化资源的分配。比如一个功能很简单的应用程序,它会调用一些我们常用的对话框或者输入面板,这需要采用统一的方式来针对不同的应用程序制定统一标准。
当我们面对Android UI优化时,有必要继续考虑资源复用。手机开发给我们的直观感觉是运行其上的软件应该尽可能的达到资源高效利用的极致,而不能像开发PC机那样,似乎有用之不尽的资源。
定义Android Layout(XML)时,有四个比较特别的标签是非常重要的,其中有三个是与资源复用有关,分别是 <viewStub
/>, <requestFocus />
, <merge />
and <include />。可是以往我们所接触的案例或者官方文档的例子都没有着重去介绍这些标签的重要性。
- <viewStub /> : 此标签可以使UI在特殊情况下,直观效果类似于设置View的不可见性,但是其更大的(R)意义在于被这个标签所包裹的Views在默认状态下不会占用任何内存空间。viewStub通过include从外部导入Views元素。
- 用法:通过android:layout来指定所包含的内容。默认情况下,ViewStub所包含的标签都属于visibility=GONE。viewStub通过方法inflate()来召唤系统加载其内部的Views。
<ViewStub android:id="@+id/stub"
android:inflatedId="@+id/subTree"
android:layout="@layout/mySubTree"
android:layout_width="120dip"
android:layout_height="40dip" />
- 用法:通过android:layout来指定所包含的内容。默认情况下,ViewStub所包含的标签都属于visibility=GONE。viewStub通过方法inflate()来召唤系统加载其内部的Views。
- <merge /> : 将在下一篇 做详细介绍。
- <include /> :可以通过这个标签直接加载外部的xml到当前结构中,是复用UI资源的常用标签。
- 用法:将需要复用xml文件路径赋予include标签的Layout属性。
<include android:id="@+id/cell1" layout="@layout/ar01" />
<include android:layout_width="fill_parent" layout="@layout/ar02" />
- 用法:将需要复用xml文件路径赋予include标签的Layout属性。
- <requestFocus /> : 标签用于指定屏幕内的焦点View。
- 用法: 将标签置于Views标签内部
<EditText id="@+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:paddingBottom="4">
<requestFocus />
</EditText>
单独将<merge />标签做个介绍,是因为它在优化UI结构时起到很重要的作用。目的是通过删减多余或者额外的层级,从而优化整个Android Layout的结构。
将通过一个例子来了解这个标签实际所产生的作用,这样可以更直观的了解<merge/>的用法。
建立一个简单的Layout,其中包含两个Views元素:ImageView 和TextView 默认状态下我们将这两个元素放在FrameLayout中。其效果是在主视图中全屏显示一张图片,之后将标题显示在图片上,并位于视图的下方。以下是xml代码:
< FrameLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent" >
< ImageView
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
android:scaleType = "center"
android:src = "@drawable/golden_gate" />
< TextView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_marginBottom = "20dip"
android:layout_gravity = "center_horizontal|bottom"
android:padding = "12dip"
android:background = "#AA000000"
android:textColor = "#ffffffff"
android:text = "Golden Gate" />
</ FrameLayout >应用上边的Layout运行的视图为:
启动 tools> hierarchyviewer.bat工具查看当前UI结构视图:
我们可以很明显的看到由红色线框所包含的结构出现了两个framelayout节点,很明显这两个完全意义相同的节点造成了资源浪费(这里可以提醒大家在开发工程中可以习惯性的通过hierarchyViewer查看当前UI资源的分配情况 ),那么如何才能解决这种问题呢(就当前例子是如何去掉多余的frameLayout节点)?这时候就要用到<merge />标签来处理类似的问题了。我们将上边xml代码中的framLayout替换成merge:
< merge xmlns:android = "http://schemas.android.com/apk/res/android" >
< ImageView
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
android:scaleType = "center"
android:src = "@drawable/golden_gate" />
< TextView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_marginBottom = "20dip"
android:layout_gravity = "center_horizontal|bottom"
android:padding = "12dip"
android:background = "#AA000000"
android:textColor = "#ffffffff"
android:text = "Golden Gate" />
</ merge >运行程序后在Emulator中显示的效果是一样的,可是通过hierarchyviewer查看的UI结构是有变化的,当初多余的 FrameLayout节点被合并在一起了,或者可以理解为将merge标签中的子集直接加到Activity的FrameLayout跟节点下(这里需要提醒大家注意:所有的Activity视图的根节点都是frameLayout)。如果你所创建的Layout并不是用framLayout作为根节点(而是应用LinerLayout等定义root标签),就不能应用上边的例子通过merge来优化UI结构。
除了上边的例子外,meger还有另外一个用法
当应用Include或者ViewStub标签从外部导入xml结构时,可以将被导入的xml用merge作为根节点表示,这样当被嵌入父级结构中后可以很好的将它所包含的子集融合到父级结构中,而不会出现冗余的节点。
另外有两点需要特别注意:
- 用法: 将标签置于Views标签内部
- <merge />只可以作为xml layout的根节点。
- 当需要扩充的xml layout本身是由merge作为根节点的话,需要将被导入的xml layout置于 viewGroup中,同时需要设置attachToRoot为True。(更多说明请参见inflate() 文档)
原文地址 hhttp://www.curious-creature.org/2009/03/01/android-layout-tricks-3-optimize-part-1/