Android布局优化作者唐韧发布于2014年1月24日|2讨论分享到:微博微信FacebookTwitter有道云笔记邮件分享稍后阅读我的阅读清单categories:Android在Android开发中,我们常用的布局方式主要有LinearLayout、RelativeLayout、FrameLayout等,通过这些布局我们可以实现各种各样的界面。与此同时,如何正确、高效的使用这些布局方式来组织UI控件,是我们构建优秀AndroidApp的主要前提之一。本篇内容就主要围绕Android布局优化来讨论在日常开发中我们使用常用布局需要注意的一些方面,同时介绍一款SDK自带的UI性能检测工具HierarchyViewer。布局原则通过一些惯用、有效的布局原则,我们可以制作出加载效率高并且复用性高的UI。简单来说,在AndroidUI布局过程中,需要遵守的原则包括如下几点:尽量多使用RelativeLayout,不要使用绝对布局AbsoluteLayout;将可复用的组件抽取出来并通过include/标签使用;使用ViewStub/标签来加载一些不常用的布局;使用merge/标签减少布局的嵌套层次;由于Android的碎片化程度很高,市面上存在的屏幕尺寸也是各式各样,使用RelativeLayout能使我们构建的布局适应性更强,构建出来的UI布局对多屏幕的适配效果越好,通过指定UI控件间的相对位置,使在不同屏幕上布局的表现能基本保持一致。当然,也不是所有情况下都得使用相对布局,根据具体情况来选择和其他布局方式的搭配来实现最优布局。1、include/的使用在实际开发中,我们经常会遇到一些共用的UI组件,比如带返回按钮的导航栏,如果为每一个xml文件都设置这部分布局,一是重复的工作量大,二是如果有变更,那么每一个xml文件都得修改。还好,Android为我们提供了include/标签,顾名思义,通过它,我们可以将这些共用的组件抽取出来单独放到一个xml文件中,然后使用include/标签导入共用布局,这样,前面提到的两个问题都解决了。例如上面提到的例子,新建一个xml布局文件作为顶部导航的共用布局。xmlcommon_navitationbar.xmlRelativeLayoutmlns:android=:tools=:layout_width=match_parentandroid:layout_height=wrap_contentandroid:background=@android:color/whiteandroid:padding=10dipButtonandroid:layout_width=wrap_contentandroid:layout_height=wrap_contentandroid:layout_alignParentLeft=trueandroid:text=Backandroid:textColor=@android:color/black/TextViewandroid:layout_width=wrap_contentandroid:layout_height=wrap_contentandroid:layout_centerInParent=trueandroid:text=Titleandroid:textColor=@android:color/black//RelativeLayout然后我们在需要引入导航栏的布局xml中通过include/导入这个共用布局。相关厂商内容平民软件CEO楼方鑫解读基于SQL的秒杀解决方案QClub:Docker专场——聚焦国内Docker创业以及企业实践敏捷咨询师吴穹《从复杂理论到自组织团队》移动互联网浪潮下网易云音乐技术和开发经验中国顶尖白帽黑客团队KeenTeam代码保护[案例:内核]相关赞助商全球软件开发大会,4月23-25日,北京,敬请期待!xmlmain.xmlRelativeLayoutmlns:android=:tools=:layout_width=match_parentandroid:layout_height=match_parentincludeandroid:layout_alignParentTop=truelayout=@layout/common_navitationbar//RelativeLayout通过这种方式,我们既能提高UI的制作和复用效率,也能保证制作的UI布局更加规整和易维护。布局完成后我们运行一下,可以看到如下布局效果,这就是我们刚才完成的带导航栏的界面。接着我们进入sdk目录下的tools文件夹下,找到HierarchyViewer并运行(此时保持你的模拟器或真机正在运行需要进行分析的App),双击我们正在显示的这个App所代表的进程。接下来便会进入hierarchyviewer的界面,我们可以在这里很清晰看到正在运行的UI的布局层次结构以及它们之间的关系。分析刚刚我们构建的导航栏布局,放大布局分析图可以看到,被include进来的common_navitationbar.xml根节点是一个RelativeLayout,而包含它的主界面main.xml根节点也是一个RelativeLayout,它前面还有一个FrameLayout等几个节点,FrameLayout就是Activity布局中默认的父布局节点,再往上是一个LinearLayout,这个LinearLayout就是包含Activity布局和状态栏的整个屏幕显示的布局父节点,这个LinearLayout还有一个子节点就是ViewStub,关于这个节点我们在后面会详细介绍。2、merge/的使用merge/标签的作用是合并UI布局,使用该标签能降低UI布局的嵌套层次。该标签的主要使用场景主要包括两个,第一是当xml文件的根布局是FrameLayout时,可以用merge作为根节点。理由是因为Activity的内容布局中,默认就用了一个FrameLayout作为xml布局根节点的父节点,这一点可以从上图中看到,main.xml的根节点是一个RelativeLayout,其父节点就是一个FrameLayout,如果我们在main.xml里面使用FrameLayout作为根节点的话,这时就可以使用merge来合并成一个FrameLayout,这样就降低了布局嵌套层次。我们修改一下main.xml的内容,将根节点修改为merge标签。xmlmain.xmlmergexmlns:android=:tools=:layout_width=match_parentandroid:background=@android:color/darker_grayandroid:layout_height=match_parentincludelayout=@layout/common_navitationbar//merge重新运行并打开HierarchyViewer查看此时的布局层次结构,发现之前多出来的一个RelativeLayout就没有了,直接将common_navigationbar.xml里面的内容合并到了main.xml里面。使用merge/的第二种情况是当用include标签导入一个共用布局时,如果父布局和子布局根节点为同一类型,可以使用merge将子节点布局的内容合并包含到父布局中,这样就可以减少一级嵌套层次。首先我们看看不使用merge的情况。我们新建一个布局文件commonnaviright.xml用来构建一个在导航栏右边的按钮布局。xmlcommon_navi_right.xmlRelativeLayoutmlns:android=:tools=:layout_width=wrap_contentandroid:layout_height=wrap_contentButtonandroid:layout_width=wrap_contentandroid:layout_height=wrap_contentandroid:layout_alignParentRight=trueandroid:text=Okandroid:textColor=@android:color/black//RelativeLayout然后修改common_navitationbar.xml的内容,添加一个include,将右侧按钮的布局导入:xmlcommon_navitationbar.xmlRelativeLayoutmlns:android=:tools=:layout_width=match_parentandroid:layout_height=wrap_contentandroid:background=@android:color/whiteandroid:padding=10dipButtonandroid:layout_width=wrap_contentandroid:layout_height=wrap_contentandroid:layout_alignParentLeft=trueandroid:text=Backandroid:textColor=@android:color/black/TextViewandroid:layout_width=wrap_contentandroid:layout_height=wrap_contentandroid:layout_centerInParent=trueandroid:text=Titleandroid:textColor=@android:color/black/includelayout=@layout/common_navi_right//RelativeLayout运行后的效果如下图,在导航栏右侧添加了一个按钮“ok”然后再运行HierarchyViewer看看现在的布局结构,发现commonnaviright.xml作为一个布局子节点嵌套在了common_navitationbar.xml下面。这时我们再将commonnaviright.xml的根节点类型改为merge。xmlcommon_navi_right.xmlmergexmlns:android=:tools=:layout_width=wrap_contentandroid:layout_height=wrap_contentButtonandroid:layout_width=wrap_contentandroid:layout_height=wrap_cont