精通安卓性能优化-第八章(二)
2014-07-22 17:46
323 查看
复用Layout
和在C/C++中直接#include相似,Android在XML布局中支持<include>标签。简单的使<include>标签包含另外一个XML布局,如Listing 8-7所示。<include>标签可以为两个目的使用:
(1) 你期望多次使用同样的布局
(2) 你的布局有个通用部分,依赖于设备配置(比如,屏幕方向:landscapte或者protrait)
Listing 8-7给出了当覆盖某些included的布局的属性的时候,如何多次包含一个布局。
Listing 8-7 多次包含布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <include android:id="@+id/myid1" android:layout="@layout/mylayout" android:layout_margin="9dip" /> <include android:id="@+id/myid2" android:layout="@layout/mylayout" android:layout_margin="9dip" /> <include android:id="@+id/myid3" android:layout="@layout/mylayout" android:layout_margin="9dip" /> </LinearLayout>
Listing 8-8给出了如何依赖于设备的方向仅包含布局一次,layout-land/mylayout.xml或者layout-port/mylayout.xml将被包含。(假设这里有两个版本的mylayout.xml,一个在res/layout-land目录,一个在res/layout-port目录)
Listing 8-8 依赖屏幕方向包含Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <include android:id="@+id/myid" android:layout="@layout/mylayout" /> </LinearLayout>
当一个布局被包含,可以覆盖一些布局的属性,比如:
(1) root view的id(android:id)
(2) layout参数(android:layout_XXX)
如Listing 8-8所展示的,当布局被inflated的时候,布局的包含是动态的。包含应该在编译的时候完成,否则Android不知道include哪个布局(layout-land/mylayout.xml或者layout-port/mylayout.xml)。这和在C/C++中直接#include不同,C/C++被预处理器在编译时候处理。
View Stubs
就像我们在第一章看到的,懒汉式初始化是延迟初始化、提升性能、潜在的节省内存(当对象从来不会被创建)的方便的技术。Android为了这个目的定义了ViewStub类。ViewStub是一个轻量级的不可见的View,可以用在你的布局中,允许懒汉式当你需要的时候inflate布局资源。Listing 8-9给出了Listing 8-8的一个修改的版本,给出如何在XML布局中使用ViewStub。
Listing 8-9 ViewStub In XML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ViewStub android:id="@+id/mystubid" android:inflatedId="@+id/myid" android:layout="@layout/mylayout" /> </LinearLayout>
当线性布局被inflate,它仅包含一个子View:一个ViewStub。被ViewStub指向的布局,@layout/mylayout,可能是一个非常复杂的布局,需要很长的时间去inflate,但是之前没有被inflate。为了inflate这个定义在mylayout.xml中的layout,在你的代码中有两个选择,如Listing 8-10和Listing 8-11所示。
Listing 8-10 在代码中inflating Layout
ViewStub stub = (ViewStub)findViewById(R.id.mystubid); View inflatedView = stub.inflate(); // inflatedView将是定义在mylayout.xml中的布局
Listing 8-11 在代码使用setVisibility() inflate布局
View view = findViewById(R.id.mystubid); view.setVisibility(View.VISIBLE); // 使用inflated布局替换view stub view = findViewById(R.id.myid); // 我们需要获取刚刚得到的inflated view
Inflate布局文件的第一种方式(在Listing 8-10)看起来更加方便,有些人可能会说它有一点问题:代码意识到view是一个stub,需要显式的去inflate它。在大多数情况下,这不是一个问题,它也将是在应用中使用ViewStub的时候推荐的方式。
Inflate布局的第二种方式在Listing 8-11给出,更加的通用的原因是它没有提到ViewStub类。然而,上面的代码仍然意识到它使用一个ViewStub的事实,因为它使用了两个固定id:R.id.mystubid和R.id.myid。为了完全通用,布局文件要定义的像8-12一样,inflate的方式像8-13一样。Listing 8-12和Listing 8-9相同,除了id是被创建的R.id.myid一个,而不是两个。相似的,Listing 8-13和Listing 8-11相同,除了R.id.mystubid被R.id.myid代替。
Listing 8-12 XML中的ViewStub,不覆盖ID
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ViewStub android:id="@+id/myid" android:layout="@layout/mylayout" /> </LinearLayout>
Listing 8-13 在代码中使用setVisibility() inflate布局
View view = findViewById(R.id.myid); view.setVisibility(View.VISIBLE); // 使用inflated布局替换view stub view = findViewById(R.id.myid); // 需要获取刚刚inflated view
作为事实,Listing 8-13不管是不是在布局中使用一个ViewStub都是可用的。如果你的代码通用性很重要,忽略在布局中是不是使用ViewStub,这个方法可以被选择。然而,findViewById()的两次调用会对性能造成负面影响。为了部分修正这个问题,因为当调用setVisibility(View.VISIBLE)的时候ViewStub将被从它的父View移除,你需要在第二次调用findViewById()之前首先检查view是否有一个parent。这样做是可选的,因为当你在你的布局中使用一个ViewStub依然需要第二次调用findViewById(),当没有使用ViewStub可以保证findViewById()只被调用一次。修改的代码Listing
8-14给出。
Listing 8-14 尽可能调用一次findViewById()
View view = findViewById(R.id.myid); view.setVisibility(View.VISIBLE); // 使用inflated layout替换view stub(如果在布局中使用stub) if (view.getParent() == null) { // 使用了stub,所以我们要使用新inflated view替换它 view = findViewById(R.id.myid); } else { // 不做任何事情,我们第一次找到的view是我们期望的 }
在Listing 8-13和Listing 8-14给出的不是通用的,你通常不需要这个方式。通常,你的代码了解布局中使用了ViewStub是可接受的,因此简单的使用8-10的代码就够了。
Layout Tools
为了帮助你创建最好的布局,Android SDK提供了两个简单的工具:hierarchyviewer和layoutopt。你可以在SDK tools目录找到这些工具。Hierarchy Viewer
Android SDK有一个非常有用的工具查看和分析应用的布局:hierarchyviewer。作为事实,Figure 8-1和Figure 8-2都是使用这个工具产生的。除了给你应用布局的细节,这个工具同样测量它需要多长时间去测量、布局、draw每个widget,识别出哪个widget需要比较长的时间去测量、布局和draw。你可以使用hierarchyviewer作为一个单独的工具,或者直接在Eclipse中使用Hierarchy View视图。
layoutopt(在SDK 16以后使用lint)
Android SDK有另外一个工具可以帮助你分析你的布局:layoutopt。这个工具分析你的布局文件,给出使布局更加有效的改变建议。比如,对Listing 8-5布局使用layoutopt工具,得到如下的输出:
The root-level <FrameLayout /> can be replaced with <merge/>
事实证明,这是Listing 8-6做的。对Listing 8-6使用layoutopt不会有任何的提醒。
TIP:使用最新的layoutopt工具,以保证你得到最好的结果。
保证layoutopt工具报的所有的问题在发布应用前有认真的对待。不优化布局会使应用变慢,而补救这样的布局通常很简单。
相关文章推荐
- 精通安卓性能优化-第八章(三)
- 精通安卓性能优化-第八章(一)
- 精通安卓性能优化-第八章(四)
- 精通安卓性能优化-第二章(四)
- 精通安卓性能优化-第三章(一)
- 精通安卓性能优化-第七章(二)
- 精通安卓性能优化-第二章(三)
- 精通安卓性能优化-第四章(一)
- 精通安卓性能优化-第五章(二)
- 精通安卓性能优化(Pro Android Apps Performance Optimization)-前言
- 精通安卓性能优化-第一章(四)
- 精通安卓性能优化-第一章(九)
- 精通安卓性能优化-第四章(二)
- 精通安卓性能优化-第五章(一)
- 精通安卓性能优化-第五章(四)
- 精通安卓性能优化-第一章(八)
- 精通安卓性能优化-第二章(二)
- 精通安卓性能优化-第六章(一)
- 精通安卓性能优化-第一章(七)
- 精通安卓性能优化-第一章(十)- 总结