APP性能之终端兼容优化分享

对于种类繁多Android设备适配. 对开发者来说, 也是除了应用逻辑以外需要重点考虑的一个重要因素. 因为这点将会直接影响到用户对应用的印象和体验. Google对此也出了很多应对措施来解决Android的碎片化.
我也来分享下我平时遇到的性能之终端兼容优化的办法:
1, 多屏幕, 多分辨率
①这点也许这是开发者遇到的最头疼的问题, 甚至导致某些开发者中途放弃Android, 转投其他平台. 其实这点并不可怕, Google为我们提供了很多resource qualifier来解决此问题. 根据不同分辨率, 不同系统版本, 不同屏幕尺寸, 不同屏幕方向, 不同语言, 不同地区, 甚至不同UI的模式, 不同的sim卡也能匹配, 具体请看下表: (附链接http://developer.android.com/guide/topics/resources/providing-resources.html)
6.png
②尽量使用Android提供的各种Drawable来绘制(BitmapDrawable, NinePatchDrawable, ShapeDrawable等等都是对适配很有用的), 详情见网址: http://developer.android.com/guide/topics/resources/drawable-resource.html
如下代码:

<?xml version="1.0" encoding="utf-8"?>

<shape xmlns:android="http://schemas.android.com/apk/res/android" >

    <gradient

        android:angle="90"

        android:endColor="#ff5f9dde"

        android:startColor="#ff3972bf" >

    </gradient>

</shape>

效果如下:
12.png
③尽量准备多套UI资源图, 针对不同分辨率的屏幕. drawable-ldpi, drawable-mdpi, drawable-hdpi是最常见的分辨率的. 别让mdpi的设备用hdpi的资源, 这样会造成消耗大量的内存, 一般mdpi的设备都硬件配置都不高.
④当layout里面用到LinearLayout时, 子View用android:layout_weight来自动排布, 也是一个用作自适应不错的选择. 就如下面代码:

<?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" >

    <Button

        android:layout_width="0dp"

        android:layout_height="wrap_content"

        android:layout_weight="1" />

    <Button

        android:layout_width="0dp"

        android:layout_height="wrap_content"

        android:layout_weight="1" />

    <Button

        android:layout_width="0dp"

        android:layout_height="wrap_content"

        android:layout_weight="1" />

    <Button

        android:layout_width="0dp"

        android:layout_height="wrap_content"

        android:layout_weight="1" />

</LinearLayout>

真机上运行效果
999.png
屏幕变化
998.png
Pad
997.png
当LinearLayout的android:orientation为horizontal时别忘了将含layout_weight属性的子View的layout_width设置成0dp. 当为vertical时, 将含layout_weight属性的子View的layout_height设置成0dp, 这样可以减少LinearLayout在onMeasure时计算量.
2, 多版本
①说到版本兼容性, 第一个想到的就要是用低版本sdk开发, 这样在所有高于设备上正常运行. 但是有个弊端就是无法使用Android高版本提供新特性.
于是这个时候"Android Compatibility package"就出场了, 这个library是Google为低版本提供一些兼容高版本的特性, 如Fragment, ViewPager等等, 开发者可以在低版本的系统使用高版本的特性.
但是如果需要同时兼容高低版本. 就需要用到android:targetSdkVersion和android:minSdkVersion, android:minSdkVersion很好理解, 就是该应用支持的最低api level的设备, android:targetSdkVersion则是用来区分是使用"Android Compatibility package"提供的兼容特性还是使用系统本身提供的.

<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="11" />

比如上面的代码, 就是最低版本是api level是7(Android 2.1), 当api level低于11(Android 3.0)就使用"Android Compatibility package"提供的兼容类(Fragment), 高于11(Android 3.0)就使用3.0提供的.
同时编译的时候需要把eclipse的project build target设置成api level高于11的
②还有个版本兼容性能用到的就是Java提供的反射机制, 这样也可以使开发者的应用在某个方法可用的时候进行调用. 这个可以通过查询开发文档进行查询. 流程看下图:
屏幕快照 2012-05-15 下午12.56.54.png
当然针对某些实例变量也能通过反射来改变, 这个就需要去查询源码, 不推荐.
3, UI优化
①layoutopt - 曾经作为独立的app于sdk/tools目录中, 高版本的sdk将他集成到ADT中了. 主要功能检测你编写的layout中哪些View是无用的, 哪些是可以两个合并到一个, 达到相同的UI效果的.
该工具报出如下警告. 以便于开发者修改. 具体大家可以Google下这个工具的用法.
11:17 This LinearLayout layout or its LinearLayout parent is useless
5:22 The root-level <FrameLayout/> can be replaced with <merge/> 10:21 This LinearLayout layout or its FrameLayout parent is useless
-1:-1 This layout has too many views: 83 views, it should have <= 80!
现在该工具已经集成到ADT了, 编写代码的同时就会显示出警告.
opt.png
②hierarchyviewer - 该工具位于sdk/tools目录中. 可以帮助开发查看自己应用View的结构和嵌套的层次, 嵌套层次太多也会对性能有影响.
屏幕快照 2012-05-15 下午1.52.22.png
整个工具基本就是呈现你的应用所使用到的View, 已经层级关系. 开发者可以通过点击节点来获取此节点的当前状态图, 同时节点下会有三个可能是红黄绿的圆点, 分别表示你的这个View在measure, layout, draw所消耗的时间和其他50%的View作对比. 就如生活中的红黄绿灯一样的效果. 绿色当然最好.
4. 代码优化
①说到代码优化, 这儿是我收集的一个表格:

行为

时间

加入一个本地变量                                                                1

加入一个成员变量                                                               4

调用String.length()                                                            5

调用空的静态本地方法                                                        5

调用空的静态方法                                                                12

调用空的虚方法                                                                   12.5

调用空的接口方法                                                               15

调用HashMap的Iterator:next()方法                               165

调用HashMap 的put() 方法                                              600

从XML展开一个视图                                                          22,000

展开一个包含1个TextView的LinearLayout                    25,000

展开一个包含6个View的LinearLayout                            100,000

展开一个包含6个TextView的LinearLayout                   135,000

运行一个空的 activity                                                       3,000,000

根据表格, 就知道应该避免做哪些不必要的操作了.
②在Android源码中也经常见到这样的写法, "将一个实例变量赋值给一个局部变量, 然后用这个局部变量"(局部缓存), 特别是在onDraw方法或者循环中. 会经常用到. 因为Java访问局部变量速度会比访问实例变量快. 这是一个用空间换时间的操作.
③尽量使用普通循环, 而不是使用使用实现Iterable接口的for each循环. 因为移动设备性能有限. Iterable循环会重复调用Iterator的hasNext()和next()方法, 从上面表格可以看出调用方法, 比访问属性更耗时.

posted on 2012-05-29 17:22  ①块腹肌  阅读(2111)  评论(0编辑  收藏  举报

导航