Android群英传读书笔记(第十章)
本章主要介绍的是android的性能优化。
## 1.布局优化
* Android UI渲染机制
在Android中,系统通过VSYNC信号出发对UI的渲染、重绘,其间隔时间是16ms。这个16ms其实就是1000ms中显示60帧画面的单位时间(玩游戏的就该知道,大于等于60帧就感觉不到卡顿)。Android系统提供了检测UI渲染时间的工具,打开“开发者选项”,选择“Profile GPU Rendering”(我的手机是“GPU呈现模式分析”),选中“On screen as bars”(我的为“在屏幕上显示为条形图”)。每一条柱状线都包括三部分,蓝色代表测量绘制Display List的时间,红色代表OpenGL渲染Display List所需要的时间,黄色代表CPU等待GPU处理的时间,中间绿色横线代表VSYNC时间16ms,需要尽量将所有条形图都控制在这条绿线之下。
* 避免Overdraw
过渡绘制会浪费很多CPU、GPU资源,例如系统默认会绘制Activity的背景,而如果再给布局绘制了重叠的背景,那么默认Activity的背景就属于无效的过渡绘制。Android系统在开发者选项中提供了这样一个检测工具--“Enable GPU Overdraw”。借助它可以判断Overdraw的次数。尽量增大蓝色的区域,减少红色的区域。
* 优化布局层级
在Android中系统对View的测量、布局和绘制都是通过遍历View树来进行的,如果View树太高,就会影响其速度,Google也建议View树的高度不宜超过10层。
* 避免嵌套过多无用布局
* 使用<include>标签重用Layout:
为了能够在不同的Layout组件中使用共通UI,就可以通过<include>标签来完成。
~~~
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0dp"
android:layout_height="0dp"
android:textSize="20sp"
android:text="this is a common ui">
</TextView>
~~~
然后在布局中进行引用:
~~~
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<include
layout="@layout/test"
android:layout_width="100dp"
android:layout_height="50dp" />
</RelativeLayout>
~~~
如果你需要在<include>标签中覆盖类似原布局中android:layout_xxxxx属性,就必须在<include>标签中同时指定android:layout_width和android:layout_height属性。
* 使用<ViewStub>实现View的延迟加载
<ViewStub>是个非常轻量级的组件,不仅不可视而且大小为0。这个布局在初始化时不需要显示,只有在某些情况下才显示出来。下面是实例代码:
~~~
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="not often use" />
</RelativeLayout>
~~~
使用<ViewStub>:
~~~
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ViewStub
android:id="@+id/view_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout="@layout/test" />
</RelativeLayout>
~~~
~~~
ViewStub viewStub= (ViewStub) findViewById(R.id.view_stub);
//下面两个方法都是用来实现延迟加载的,区别是inflate()方法会返回引用的布局。
viewStub.setVisibility(View.VISIBLE);
View view=viewStub.inflate();
TextView tv= (TextView) view.findViewById(R.id.tv);
~~~
<ViewStub>标签与设置View.GONE这种方式的区别在于<ViewStub>标签只在显示时渲染整个布局,而设置View.GONE这种方式在初始化时就已经加载了,所以相比之下<ViewStub>更有效率。
* Hierarchy Viewer
这是个用来测试布局冗余的工具,具体用法就不做记录了。介绍在此
## 2.内存优化
* 内存介绍
* 寄存器:速度最快的存储场所,因为寄存器位于处理器内部,在程序中无法控制。
* 栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中。
* 堆:堆内存用来存放由new创建的对象和数组,在堆中分配的内存,由Java虚拟机的自动垃圾回收器(GC)来管理。
* 静态存储区域:是指在固定的位置存放应用程序运行时一直存在的数据,Java在内存中专门划分了一个静态存储区域来管理一些特殊的数据变量如静态的数据变量。
* 常量池:就是该类型所用到常量的一个有序集合,包括直接常量(基本类型,String)和对其他类型、字段和方法的符号引用。
* 内存优化实例
* Bitmap优化
Bitmap是造成内存占用过高甚至是OOM的最大威胁,可以通过以下技巧进行优化
① 使用适当分辨率和大小的图片:例如在图片列表界面可以使用图片的缩略图thumbnails,而在显示详细图片的时候再显示原图;或者在对图像要求不高的地方,尽量降低图片的精度。
② 及时回收内存:一旦使用完Bitmap后,一定要及时使用bitmap.recycle()方法释放内存资源。自Android3.0后,由于Bitmap被放到了堆中,其内存由GC管理,就不需要释放了。
③ 通过内存缓存LruCache和DiskLruCache可以更好地使用Bitmap。
* 代码优化
任何Java类都将占用大约500字节的内存空间,创建一个类的实例会消耗大约15字节内存。从代码的实现上,也可以对内存进行优化。
① 对常量使用static修饰符。
② 使用静态方法,静态方法会比普通方法提高15%左右的访问速度。
③ 减少不必要的成员变量,这点在Android Lint工具上已经集成检测了。
④ 减少不必要对象,使用基础类型会比使用对象更加节省资源,同时更应该避免频繁创建短作用域的变量。
⑤ 尽量不要使用枚举、少用迭代器。
⑥ 对Cursor、Receiver、Sensor、File等对象,要非常注意对它们的创建、回收和注册、反注册。
⑦ 避免使用IOC框架,IOC通常使用注解、反射来进行实现,大量使用反射会带来性能的下降。
⑧ 使用RenderScript、OpenGL来进行非常复杂的绘图操作。
⑨ 使用SurfaceView来代替View进行大量、频繁的绘图操作。
⑩ 尽量使用视图缓存,而不是每次都执行inflate()解析视图。
本章节后面还介绍了Lint、MemoryMonitor、TraceView、MAT等工具来分析内存的使用情况,