对于种类繁多Android设备适配. 对开发者来说, 也是除了应用逻辑以外需要重点考虑的一个重要因素. 因为这点将会直接影响到用户对应用的印象和体验. Google对此也出了很多应对措施来解决Android的碎片化.
我也来分享下我平时遇到的性能之终端兼容优化的办法:
1, 多屏幕, 多分辨率
①这点也许这是开发者遇到的最头疼的问题, 甚至导致某些开发者中途放弃Android, 转投其他平台. 其实这点并不可怕, Google为我们提供了很多resource qualifier来解决此问题. 根据不同分辨率, 不同系统版本, 不同屏幕尺寸, 不同屏幕方向, 不同语言, 不同地区, 甚至不同UI的模式, 不同的sim卡也能匹配, 具体请看下表: (附链接http://developer.android.com/guide/topics/resources/providing-resources.html)
②尽量使用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>
效果如下:
③尽量准备多套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>
真机上运行效果
屏幕变化
Pad
当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提供的反射机制, 这样也可以使开发者的应用在某个方法可用的时候进行调用. 这个可以通过查询开发文档进行查询. 流程看下图:
当然针对某些实例变量也能通过反射来改变, 这个就需要去查询源码, 不推荐.
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了, 编写代码的同时就会显示出警告.
②hierarchyviewer - 该工具位于sdk/tools目录中. 可以帮助开发查看自己应用View的结构和嵌套的层次, 嵌套层次太多也会对性能有影响.
整个工具基本就是呈现你的应用所使用到的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()方法, 从上面表格可以看出调用方法, 比访问属性更耗时.