标签:
参考地址:http://developer.android.com/training/improving-layouts/optimizing-layout.html
布局是Android应用程序的关键部分,直接影响到用户体验。如果实现的不好,布局会消耗大量内存,应用程序UI会变得缓慢。Android SDK包含工具来帮助你识别布局性能问题,结合最佳实践,你将能够实现流畅的滚动体验和一个最低内存的占用。
我们有一个误解,就是使用基本的布局结构,可以实现最有效率的布局。加到App中的布局都会经历初始化、布局和绘制的阶段。比如LinearLayout可能会导致一个过深的视图层级。另外,嵌套在LinearLayout中的每一个View使用layout_weight属性时,性能更低,因为它需要被计算(onMeasure)两次。这在ListView 或 GridView中尤甚,因为这两个widget中的布局重复的出现。
Android SDK提供了一个叫View Hierarchy的工具。,可以帮助你在App运行时检测布局的结构和瓶颈。hierarchyviewer工具位于/tools/目录中。打开之后可以选择设备以及运行的程序,点击* Load View Hierarchy*,例如下图是LinearLayout嵌套的View Hierarchy: 
 
这是一个三层的视图结构,我们看到在第二层的LinearLayout上有一些问题。点击它会出现下图: 
 
渲染一个列表item所花时间如下: 
-Measure: 0.977ms 
-Layout: 0.167ms 
-Draw: 2.717ms 
我们看到在draw上花了较多的时间,这样可以针对绘制进行优化。
上述描述的布局性能问题是来自嵌套的LinearLayout,我们可以使用扁平的布局方式来提升,即减少它的视图层级。RelativeLayout是一个较好的选择,当使用RelativeLayout布局时,你会发现视图层级变成了2级。看上去如下: 
 
选择渲染一个列表item所花时间如下: 
Measure: 0.598ms 
Layout: 0.110ms 
Draw: 2.146ms 
看到时间上有一些提升,但因为是列表项,当列表数据很多时,性能就提升了很多了。 
大多数时候LinearLayout性能较低,是因为layout_weight属性的使用。
Lint已经取代Layoutopt工具,它具有更强大的功能。一些Lint的规则如下:
Lint集成到Android Studio中,无论何时编译代码它都会自动执行。使用Lint可以对特定的构建变量或全部的构建变量进行监视。 
在Android Studio中,File>Settings>Project Settings,可以设置监视配置。 
 
Lint可以自动修复一些问题,或者提供修复建议,还可以直接跳转到对应的代码进行审查。
参考地址:http://developer.android.com/training/improving-layouts/reusing-layouts.html 
在Android中可以使用 和 来嵌套一个布局到当前布局中。 
重用布局特别强大,它允许你创建可重用的复杂的布局。比如,一个Toggle按钮,或自定义的带描述文本的进度条。这也意味着在多个应用程序中通用的布局元素可以提取,单独管理,然后被包含在其它布局中。因此,尽管你可以通过编写一个自定义View创建个人的UI组件,你也可以更轻易的重用一个布局文件。
例如,下面是一个titlebar.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/titlebar_bg">
    <ImageView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:src="@drawable/gafricalogo" />
</FrameLayout>
将上面的titlebar加到自己的当前布局中:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/app_bg"
    android:gravity="center_horizontal">
    <include layout="@layout/titlebar"/>
    <TextView android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:text="@string/hello"
              android:padding="10dp" />
    ...
</LinearLayout>
你也可以覆盖被include进来的布局的root View所有的布局参数(任意android:layout_*属性),例如:
<include android:id="@+id/news_title"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         layout="@layout/title"/>
然而,在include布局中药覆盖布局参数,务必要覆盖android:layout_height 和 android:layout_width参数,这样布局才能正确的生肖。
标签有助于消除视图层次中不用的ViewGroup。例如,当你的主布局中有一个垂直的LinearLayout,其中有两个连续的View可以在多个布局中重用,然后将这个重用的布局组织起来需要一个根View,如果使用LinearLayout作为根View,那么会导致增加View的层次结构,这个LinearLayout没有任何实际意义,也会拖慢UI性能。 
这时我们使用标签,可以避免这种现象发生:
<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>
现在,你将这个布局使用嵌套到另一个布局中,系统会直接忽略标签,直接将两个按钮加到布局中,取代include标签。
http://developer.android.com/training/improving-layouts/loading-ondemand.html#ViewStub 
有时需要加载一个暂时不需要的复杂视图,是比较消耗内存等资源且会影响界面的加载速度的。我们使用ViewStub来满足这个需求。
ViewStub是一个轻量的view,没有尺寸,不需要在布局中draw任何东西。每一个ViewStub都只需要指定android:layout属性即可,这个属性标识ViewStub要解析的布局。
<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的布局,调用setVisibility(View.VISIBLE) 或 inflate()设置它可见即可:
((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
一旦ViewStub设置可见或inflate过之后,ViewStub 就不再是视图层级中的元素了,它会被inflate出来的布局替换,这个布局的rootView的id为ViewStub中的android:inflatedId属性指定的。
注意:ViewStub的一个缺点是现在不支持标签的解析。
参考地址:http://developer.android.com/training/improving-layouts/smooth-scrolling.html 
为了让ListView滚动平滑,需要让主线程摆脱繁重的任务处理,确保任何的网络操作、磁盘IO操作、SQL操作都在一个单独的线程中运行。
使用后台线程(“worker thread”),给主线程(UI线程)减轻负担,让其专注于draw UI。AsyncTask 提供一个简单的方式实现在主线程异步加载数据:
// Using an AsyncTask to load the slow images in a background thread
new AsyncTask<ViewHolder, Void, Bitmap>() {
    private ViewHolder v;
    @Override
    protected Bitmap doInBackground(ViewHolder... params) {
        v = params[0];
        return mFakeImageLoader.getImage();
    }
    @Override
    protected void onPostExecute(Bitmap result) {
        super.onPostExecute(result);
        if (v.position == position) {
            // If this item hasn‘t been recycled already, hide the
            // progress and set and show the image
            v.progress.setVisibility(View.GONE);
            v.icon.setVisibility(View.VISIBLE);
            v.icon.setImageBitmap(result);
        }
    }
}.execute(holder);
从Android 3.0 (API level 11)开始,我们可以使用AsyncTask的新特性,使用多核心处理器。我们使用executeOnExecutor()而不是execute()来执行任务,它允许同时处理多个后台任务基于可用的处理器的数量。
在滚动ListView时会频繁调用findViewById()方法,这样是非常消耗性能的,我们使用ViewHolder来解决这类问题:
static class ViewHolder {
  TextView text;
  TextView timestamp;
  ImageView icon;
  ProgressBar progress;
  int position;
}
然后填充和存储ViewHolder如下:
ViewHolder holder = new ViewHolder();
holder.icon = (ImageView) convertView.findViewById(R.id.listitem_image);
holder.text = (TextView) convertView.findViewById(R.id.listitem_text);
holder.timestamp = (TextView) convertView.findViewById(R.id.listitem_timestamp);
holder.progress = (ProgressBar) convertView.findViewById(R.id.progress_spinner);
convertView.setTag(holder);
现在你可以很容易地访问每个View,不需要findViewById(),节省宝贵的处理器时间片。
标签:
原文地址:http://blog.csdn.net/ada_dengpan/article/details/51108687