网站首页 > 编程文章 正文
2015年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App,课程专题不仅仅介绍了Android系统中有关性能问题的底层工作原理,同时也介绍了如何通过工具来找出性能问题以及提升性能的建议。
本文抛砖引玉,意在让Android开发者在一个又一个业务实现后,能够看到另一个更广阔的天地,摆脱自已在编码或者UI设计方面的局限。
1.UI渲染
大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能。从设计师的角度,他们希望App能够有更多的动画、图片等时尚元素来实现流畅的用户体验。但是Android系统很有可能无法及时完成那些复杂的界面渲染操作。Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成。
如果你的某个操作花费时间是24ms,系统在得到VSYNC信号的时候就无法进行正常渲染,这样就发生了丢帧现象。那么用户在32ms内看到的会是同一帧画面。
当设计上追求更华丽的视觉效果的时候,我们就容易陷入采用越来越多的层叠组件来实现这种视觉效果的怪圈。这很容易导致大量的性能问题,为了获得最佳的性能,我们必须尽量减少Overdraw的情况发生。
(1)使用抽象布局标签
故此布局优化也是很重要,解决方法是使用抽象布局标签(include, viewstub, merge)、去除不必要的嵌套和View节点、减少不必要的infalte及其他Layout方面可调优点。
● <include>标签
include标签常用于将布局中的公共部分提取出来供其他layout共用,以实现布局模块化,这在布局编写方便提供了大大的便利。
● <viewstub>标签
viewstub标签同include标签一样可以用来引入一个外部布局,不同的是,viewstub引入的布局默认不会扩张,既不会占用显示也不会占用位置,从而在解析layout时节省cpu和内存。
● <merge>标签
在使用了include后可能导致布局嵌套过多,多余不必要的layout节点,从而导致解析变慢,不必要的节点和嵌套可通过hierarchy viewer(下面布局调优工具中有具体介绍)或设置->开发者选项->显示布局边界查看。
(2)去除不必要的嵌套和View节点
● 首次不需要使用的节点设置为GONE或使用viewstub
● 使用RelativeLayout代替LinearLayout
大约在Android4.0之前,新建工程的默认main.xml中顶节点是LinearLayout,而在之后已经改为RelativeLayout,因为RelativeLayout性能更优,且可以简单实现LinearLayout嵌套才能实现的布局。
4.0及以上Android版本可通过设置->开发者选项->显示布局边界打开页面布局显示,看看是否有不必要的节点和嵌套。4.0以下版本可通过hierarchy viewer查看。
(3)减少不必要的infalte
对于inflate的布局可以直接缓存,用全部变量代替局部变量,避免下次需再次inflate,如上面ViewStub示例中的。
(4)其他点
● 用SurfaceView或TextureView代替普通View
SurfaceView或TextureView可以通过将绘图操作移动到另一个单独线程上提高性能。
普通View的绘制过程都是在主线程(UI线程)中完成,如果某些绘图操作影响性能就不好优化了,这时我们可以考虑使用SurfaceView和TextureView,他们的绘图操作发生在UI线程之外的另一个线程上。
因为SurfaceView在常规视图系统之外,所以无法像常规试图一样移动、缩放或旋转一个SurfaceView。TextureView是Android4.0引入的,除了与SurfaceView一样在单独线程绘制外,还可以像常规视图一样被改变。
● 使用RenderJavascript
RenderScript是Adnroid3.0引进的用来在Android上写高性能代码的一种语言,语法给予C语言的C99标准,他的结构是独立的,所以不需要为不同的CPU或者GPU定制代码。
● 使用OpenGL绘图
Android支持使用OpenGL API的高性能绘图,这是Android可用的最高级的绘图机制,在游戏类对性能要求较高的应用中得到广泛使用。
Android 4.3最大的改变,就是支持OpenGL ES 3.0。相比2.0,3.0有更多的缓冲区对象、增加了新的着色语言、增加多纹理支持等等,将为Android游戏带来更出色的视觉体验。
● 尽量为所有分辨率创建资源
减少不必要的硬件缩放,这会降低UI的绘制速度,可借助Android asset studio。
2.代码优化
主要介绍 Java代码中性能优化方式及网络优化,包括缓存、异步、延迟、数据存储、算法、JNI、逻辑等优化方式。
(1)降低执行时间
这部分包括:缓存、数据存储优化、算法优化、JNI、逻辑优化、需求优化几种优化方式。
● 缓存
缓存主要包括对象缓存、IO缓存、网络缓存、DB缓存,对象缓存能减少内存的分配,IO缓存减少磁盘的读写次数,网络缓存减少网络传输,DB缓存较少Database的访问次数。
在内存、文件、数据库、网络的读写速度中,内存都是最优的,且速度数量级差别,所以尽量将需要频繁访问或访问一次消耗较大的数据存储在缓存中。
Android中常使用缓存:
a. 线程池
b. Android图片缓存、Android图片Sdcard缓存、数据预取缓存。
c. 消息缓存
通过handler.obtainMessage复用之前的message,如下:
1 | handler.sendMessage(handler.obtainMessage(0, object)); |
d. ListView缓存
e. 网络缓存
数据库缓存http response,根据http头信息中的Cache-Control域确定缓存过期时间。
f. 文件IO缓存
使用具有缓存策略的输入流,BufferedInputStream替代InputStream,BufferedReader替代Reader,BufferedReader替代BufferedInputStream.对文件、网络IO皆适用。
g. layout缓存
h. 其他需要频繁访问或访问一次消耗较大的数据缓存
● 数据存储优化
包括数据类型、数据结构的选择。
数据类型选择:
字符串拼接用StringBuilder代替String,在非并发情况下用StringBuilder代替StringBuffer。如果你对字符串的长度有大致了解,如100字符左右,可以直接new StringBuilder(128)指定初始大小,减少空间不够时的再次分配。
64位类型如long double的处理比32位如int慢。
使用SoftReference、WeakReference相对正常的强应用来说更有利于系统垃圾回收。
final类型存储在常量区中读取效率更高,LocalBroadcastManager代替普通BroadcastReceiver,效率和安全性都更高。
● 算法优化
这个主题比较大,需要具体问题具体分析,尽量不用O(n*n)时间复杂度以上的算法,必要时候可用空间换时间。
查询考虑hash和二分,尽量不用递归。可以从结构之法 算法之道或微软、Google等面试题学习。
● JNI
Android应用程序大都通过Java开发,需要Dalvik的JIT编译器将Java字节码转换成本地代码运行,而本地代码可以直接由设备管理器直接执行,节省了中间步骤,所以执行速度更快。不过需要注意从Java空间切换到本地空间需要开销,同时JIT编译器也能生成优化的本地代码,所以糟糕的本地代码不一定性能更优。
● 逻辑优化
这个不同于算法,主要是理清程序逻辑,减少不必要的操作。
● 需求优化
这个就不说了,对于sb的需求可能带来的性能问题,只能说做为一个合格的程序员不能只是执行者,要学会说NO。不过不能拿这种借口敷衍产品经理哦。
(2)异步,利用多线程提高TPS
充分利用多核Cpu优势,利用线程解决密集型计算、IO、网络等操作。
在Android应用程序中由于系统ANR的限制,将可能造成主线程超时操作放入另外的工作线程中。在工作线程中可以通过handler和主线程交互。
(3)提前或延迟操作,错开时间段提高TPS
● 延迟操作
不在Activity、Service、BroadcastReceiver的生命周期等对响应时间敏感函数中执行耗时操作,可适当delay;
Java中延迟操作可使用ScheduledExecutorService,不推荐使用Timer.schedule;
Android中除了支持ScheduledExecutorService之外,还有一些delay操作,如
handler.postDelayed,handler.postAtTime,handler.sendMessageDelayed,View.postDelayed,AlarmManager定时等。
● 提前操作
对于第一次调用较耗时操作,可统一放到初始化中,将耗时提前。如得到壁纸wallpaperManager.getDrawable()。
(4)网络优化
以下是网络优化中一些客户端和服务器端需要尽量遵守的准则:
a. 图片必须缓存,最好根据机型做图片做图片适配;
b. 所有http请求必须添加httptimeout;
c. 开启gzip压缩;
d. api接口数据以json格式返回,而不是xml或html;
e. 根据http头信息中的Cache-Control及expires域确定是否缓存请求结果;
f. 确定网络请求的connection是否keep-alive;
g. 减少网络请求次数,服务器端适当做请求合并;
h. 减少重定向次数;
i. api接口服务器端响应时间不超过100ms。
以上的每个小技巧,希望它能成为你日常代码的一部分,然后你就会看到意想不到的结果。
作者简介:程家兴,英文名Tonyee,校导Android开发工程师,曾任多家公司技术部组长,熟悉服务端与移动端技术,拥有6年开发经验。
猜你喜欢
- 2024-09-28 Flutter 日记 | 修改 App 图标、名称、启动页
- 2024-09-28 《神力科莎:竞速》即日开跑,首批购买玩家可免费获「洲际GT包」
- 2024-09-28 PKS系统第25课-报警组的组态和使用
- 2024-09-28 官方详解谷歌 Play 商店新格式 AAB:8 月起实施取代 APK
- 2024-09-28 像大牛一样写代码:31个Android 开发者工具
- 2024-09-28 工作笔记 - android APP开机自启动及通过adb安装系统级apk
- 2024-09-28 Android 用vector画一个朦胧版的冰墩墩
- 2024-09-28 这些小工具让你的Android 开发更高效
- 2024-09-28 unity 代码加密方案(unity il2cpp加密)
- 2024-09-28 程序员高效率实用工具推荐(web开发+爬虫+数据库+……)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- spire.doc (59)
- system.data.oracleclient (61)
- 按键小精灵源码提取 (66)
- pyqt5designer教程 (65)
- 联想刷bios工具 (66)
- c#源码 (64)
- graphics.h头文件 (62)
- mysqldump下载 (66)
- sqljdbc4.jar下载 (56)
- libmp3lame (60)
- maven3.3.9 (63)
- 二调符号库 (57)
- 苹果ios字体下载 (56)
- git.exe下载 (68)
- diskgenius_winpe (72)
- pythoncrc16 (57)
- solidworks宏文件下载 (59)
- qt帮助文档中文版 (73)
- satacontroller (66)
- hgcad (64)
- bootimg.exe (69)
- android-gif-drawable (62)
- axure9元件库免费下载 (57)
- libmysqlclient.so.18 (58)
- springbootdemo (64)
本文暂时没有评论,来添加一个吧(●'◡'●)