精通安卓性能优化-第八章(一)

来源:互联网 发布:网络机柜定制 编辑:程序博客网 时间:2024/05/19 03:30

第八章 Graphics

你经常需要花费很多时间去定义你的应用的样子。不管是一个使用标准Android控件的e-mail应用或者使用OpenGL ES的游戏,当浏览应用商店比如Android市场或者Amazon应用市场的时候,你的应用看起来什么样子是用户首先会注意到的。
一个看起来很好的应用,但是图片的显示很慢或者更新很慢,很可能不会有很大的点击量。相似的,一个游戏如果渲染质量很高,但是帧率很低,很可能会被用户忽略。评论最终推动应用程序的成功,因此你的应用要不只是秀色可餐很重要。
在本章学习使用不同的技术和工具去优化你的布局,以及一些技术去优化OpenGL ES渲染,达到更好的帧率或者减少电能消耗。

优化布局

现在你应该已经熟悉XML布局和setContentView()方法。这个方法的通常使用方式在Listing 8-1给出。尽管许多人认为定义布局很简单,特别是在Eclipse中使用图形布局,很容易得意忘形并且远离优化的布局。本部分提供了几个简单方式简化布局,并加速布局的inflation。

Listing 8-1 通常setContentView()调用

public class MyActivity extends Activity {    private static final String TAG = "MyActivity";        /** Called when the activity is first created. */    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);                // 调用setContentView()去inflate和set layout(在main.xml中定义)        setContentView(R.layout.main);        ...    }    ...}

尽管这只是一个非常简单的调用,当调用setContentView()的时候,在引擎盖下发生了几件事情:
(1) Android读取应用的资源数据(在APK文件中,存储在内部存储器或者SD card)。
(2) 资源数据被解析,布局被inflated
(3) inflated布局成为activity的最顶级视图
这个调用需要多长时间依赖于布局的复杂度:资源数据越大,解析越慢;越多的类需要初始化,布局初始化的越慢。
当你在Eclipse中创建一个应用,在main.xml产生默认的布局,如果Listing 8-2所示。Textview的文本内容定义在strings.xml。
Listing 8-2 默认布局

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical">        <TextView        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="@string/hello" />        </LinearLayout>

setContentView()的调用如Listing 8-1所示,在Samsung Galaxy Tab 10.1上,使用这个layout需要大概17毫秒完成。尽管这很快,它只是一个极其简单的布局,不真正代表一个通常的Android应用:只有两个类被初始化(LinearLayout和TextView),在XML中指定了非常少的属性。

NOTE:布局可以通过代码创建,但是通常选择XML。

在添加多个widget到默认的布局,达到总共30个widget之后(包括ScrollView,EditText和ProgressBar),setContentView()需要大约163毫秒完成。
就像可以看到的,inflate一个布局需要的时间几乎随着创建widget的数量的增加线性增长。而且,调用setContentView()占用了从onCreate()开始到onResume()结束几乎99%的时间。
你可以通过从布局中简单的添加widget或者移除widget执行自己的测量。使用Eclipse的XML的图形布局视图使得它非常简单。如果你已经定义了应用的布局,第一件需要做的事情是测量需要多少时间去inflate它。因为这个layout通常在应用的onCreate()方法里面去inflate,它需要的时间将会直接影响到activity的启动时间,以及你的应用的启动时间。因此推荐你尝试最小化花费在inflate布局上的时间。
为了达到这个目标,几个技术是可用的,大多数基于同样的原则:减少创建对象的数量。你可以通过使用达到同样的视觉效果的不同的布局,通过消除不必要的对象,或者延缓对象的创建去达到这个目标。

RelativeLayout

线性布局通常是应用开发者学习使用的第一个布局。作为事实,这个布局在Listing 8-1默认布局中作为部分给出,因此是开发者熟悉的第一个ViewGroup。它同样是一个理解起来非常简单的布局,因为一个线性布局是widget的一个容器,水平对齐或者竖直对齐。
大多数新的Android应用开发者单纯使用线性布局去达到设计目标。Listing 8-3给出了一个单纯的线性布局实例。

Listing 8-3 单纯的Linear Layout

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="horizontal" >            <TextView            android:id="@+id/text1"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="str1"            android:textAppearance="?android:attr/textAppearanceLarge"             />        <TextView            android:id="@+id/text2"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="str2"            android:textAppearance="?android:attr/textAppearanceLarge"             />            </LinearLayout>        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="horizontal" >            <TextView            android:id="@+id/text3"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="str3"            android:textAppearance="?android:attr/textAppearanceLarge"             />        <TextView            android:id="@+id/text4"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="str4"            android:textAppearance="?android:attr/textAppearanceLarge"             />            </LinearLayout>        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="horizontal" >            <TextView            android:id="@+id/text5"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="str5"            android:textAppearance="?android:attr/textAppearanceLarge"             />        <TextView            android:id="@+id/text6"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="str6"            android:textAppearance="?android:attr/textAppearanceLarge"             />            </LinearLayout>    </LinearLayout>

布局的核心view是6个text view。这里的四个线性布局简单的用来确定位置。
这个布局暴漏了两个问题:
(1) 因为单纯的线性布局,布局的层级变得更深(使得布局和键盘消息处理更慢)
(2) 超过10个对象,其中4个仅仅用来定位
这两个问题通过使用一个简单的relative布局替换这些线性布局很简单解决,如Listing 8-4所示。
Listing 8-4 Relative Layout

<?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"    android:orientation="vertical" >    <TextView            android:id="@+id/text1"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignParentLeft="true"            android:layout_alignParentTop="true"            android:text="str1"            android:textAppearance="?android:attr/textAppearanceLarge"             />            <TextView            android:id="@+id/text2"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_toLeftOf="@id/text1"            android:layout_alignParentTop="true"            android:text="str2"            android:textAppearance="?android:attr/textAppearanceLarge"             />        <TextView            android:id="@+id/text3"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignParentLeft="true"            android:layout_below="@id/text1"            android:text="str3"            android:textAppearance="?android:attr/textAppearanceLarge"             />                <TextView            android:id="@+id/text4"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_toRightOf="@id/text3"            android:layout_below="@id/text2"            android:text="str4"            android:textAppearance="?android:attr/textAppearanceLarge"             />        <TextView            android:id="@+id/text5"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_below="@id/text3"            android:layout_alignParentLeft="true"            android:text="str5"            android:textAppearance="?android:attr/textAppearanceLarge"             />                <TextView            android:id="@+id/text6"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_toRightOf="@id/text5"            android:layout_below="@id/text4"            android:text="str6"            android:textAppearance="?android:attr/textAppearanceLarge"             />    </RelativeLayout>

就像你可以看到的,所有的6个text view在一个relative布局内,因此仅创建了7个对象而不是10个。这个布局同样没有过去那么深:text view现在在一层。定位widget的关键在layout_XXX属性。Android定义了许多这样的属性,可以用来决定不同元素的位置:




NOTE:一些属性是某些布局特有的。比如,layout_column, layout_cloumnSpan, layout_row,和layout_rowSpan是grid布局特有的。

Relative布局在List项中特别重要,因为在任何给定的时间再屏幕上显示10个更多项对应用来说很普遍。

Merging Layouts

另外一个减少布局层次的高度的是方法是使用<merge>标签merge布局。特别是在你的布局中顶层元素是FrameLayout的情况下,如Listing 8-5所示。
Listing 8-5 Frame Layout

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:id="@+id/my_top_layout">        <ImageView        android:layout_width="match_parent"        android:layout_height="match_parent" />    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="@string/hello"         />    </FrameLayout>
因为activity的content view的父view同样是一个FrameLayout, 你将最终在布局中使用两个FrameLayout:
(1) 你自己的FrameLayout
(2) Activity的content view的父view,另外一个FrameLayout,仅有一个子view(你自己的FrameLayout)
Figure 8-1给出了你将得到的布局,假设你的自己的FrameLayout有两个子view:一个ImageView和一个TextView。

Figure 8-1 FrameLayout作为另一个FrameLayout的子布局

FrameLayout太多,你可以通过使用<merge>标签替换你自己的FrameLayout来减少布局层级。这样做,安卓简单的把<merge>标签的子view attach到父FrameLayout。Listing 8-6给出了新的XML布局。

Listing 8-6 Merge标签

<?xml version="1.0" encoding="utf-8"?><merge xmlns:android="http://schemas.android.com/apk/res/android">        <ImageView        android:layout_width="match_parent"        android:layout_height="match_parent" />    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="@string/hello"         />    </merge>

就像你可以看到的,使用<merge>标签替换<FrameLayout>标签。Figure 8-2给出了结果布局。
Figure 8-2 使用<merge />替换<FrameLayout />




0 0
原创粉丝点击