“一本正经地胡说八道”用日语怎么说?大概是「真面目にふざけている」吧。这篇日志大概就是这么一个意思?算法
一直以来都想对Android APP开发的性能调优作一下总结,其实性能调优涉及到多方面的工做,每次有一些心得我都会记录下来,零零散散记录了不少,最近发现许多地方重复了,感受仍是得作一下整理的,知识就是这么牢固起来的。数据库
“APP卡顿”是一个问题,咱们既须要知道怎么查找出哪里形成卡顿,也须要掌握规避这些卡顿的技巧,因此这个话题能够分为“如何定位APP中的性能问题”和“提升性能须要注意哪些点”这两部分,后续在陆续对这两点展开讨论吧,今天先从总体分析下问题存在的缘由。segmentfault
开始正题以前先让我吐一吐苦水吧。设计模式
我我的喜欢日语,因此学了好久的日语了,一样我也是由于喜欢Android,才开始跳进了Android开发这个坑。不过很是遗憾的是,就和“当初我在日语班里,周围大部分人只是由于日语专业比较轻松才选了它”同样,我周围的Android研发同事大部分用的是IOS手机,甚至有人问过我“我说你工资也不至于那么低吧,怎么天天都拿着安卓手机”。产品则是每次都说“你这个交互和IOS的不同,我需求文档里写得清清楚楚,要保持一致的用户体验”。设计的话,我历来就没有碰见过拿安卓手机的。缓存
我尝试说过Android不比IOS差,可是没人站在我这边。性能优化
自从Android系统诞生以来一直都有一个疑问,“为何Android手机这么卡?”,不管Android设备的硬件再怎么升级,版本再怎么迭代,“Android比IOS卡顿”彷佛成为一个板上钉钉的事实。Android手机真的卡么?服务器
至少在Android Kitkat以前,许多Android开发者都会选择回避这个问题;Kitkat以后,有一部分开发者已经有底气回答这个问题了;随着Android Lollipop以及Marshmallow前后的出现,我以为Android开发者均可以自信地回答说“Android不卡”了。网络
在一个公司内部分享会中,国内Android领域的大神罗升阳在分享他对ART模式的研究中说到,继Kitkat采用了ART模式后,Lollipop中,除了UI线程以外又提供了一条专门用于执行动画的线程,这样一来UI线程就能够专一于展现数据和响应用户的输入,这让Android的流畅度又上了一个档次。IOS是闭源的因此咱们无从得知,可是有人分析说IOS之因此这么流畅很大一个缘由就是它大概也采用了相似动画线程的机制。老罗也相信“Android系统不会比IOS卡,甚至已经比它还流畅”。框架
这可不是随便说说,个人Nexus5升级到Lollipop以后我以为它已经能够匹敌同事的IPhone6了,前不久升级到Marshmallow内测版,我更是以为它已经拉开IPhone6一个档次了。异步
那为何许多人以为Android用起来仍是比IOS卡?注意老罗说“Android系统”比IOS流畅,而不是“Android应用”,言下之意就是Android系统自己不卡,卡的是设备开发商开发的ROM以及开发者开发的第三方APP。我我的以为Android卡顿问题大体有如下的缘由。
如今Lollipop甚至Kitkat的普及率还不算很高,更别谈Marshmallow了,这是Android碎片化的问题决定的,具体缘由有兴趣的能够本身Google,网上一堆比我在这里吹的靠谱多的分析。
固然这里也有很大一部分是设备开发商的锅,Google开源的AOSP项目只能兼容Nexus系列手机的硬件,若是第三方设备开发商须要使用AOSP的话,最起码也要把AOSP里面的驱动部分改为能兼容本身的设备的,此外,他们还喜欢把系统UI风格作成本身家的,这起码也要本身写一个Launcher应用和自定义主题(这也是许多Android ROM被吐槽成换皮肤的缘由);此外有一些特点功能,好比指纹设备,Android Marshmallow以前AOSP并无这个功能,因此开发商就得本身出解决方案了。这一系列的工做,形成了开发商没法在Google发布Android的新版本以后迅速升级自家Android设备的系统。
Android4.0版本相比以前的版本性能上优化了许多,无奈我接触的Android产品都要求最低支持Android2.3,有一款SDK甚至要求支持到Android1.6并且不能使用Support库(今年但是2015年!你能想象一个手动写Thread去控制一个复杂的属性动画的效果有多糟糕吗?),因此Android开发者须要作一大堆向下兼容的工做,有时候为了保证在一些奇葩机型的兼容性,选择了保守的实现方式而不采用Android的新特性。向下兼容的逻辑使得APP即便在高级版本的Android系统上也要跑一堆没用的判断逻辑,若是这些逻辑出如今循环体内则更糟糕;采用保守的实现方式,使得APP没法发挥新版本Android的性能,即便用户手机升级了Android系统版本也享♂受新版本带来的体验。此外,即便许多新的APP产品都选择最低支持Android4.0,这使得许多新特性都不用Support库支持就能直接使用,可是许多手机设备仍是没法升级到Android4.4版本的系统,即便有,不少ROM仍是把ART模式给严格了,没法体验其脱胎换骨版的顺畅。
最近支付宝被Google Play下架了,缘由就是其“从Play市场之外的服务器下载可执行代码”,意思就是它使用了动态加载技术。Android的动态加载也不是新鲜的事物了,个人项目中也采用过,简单来讲原理就是Android APP采用“APK空壳+可执行代码”的开发方式,APK只是一个空壳,用户安装过一次后就不用从新安装了,若是须要升级APP,APK空壳会从服务器下载新的可执行代码,更换本地的便可完成升级(具体实现方案如今网上一堆教程,也能够参考我Github上的相关项目)。采用这种开发方式,开发者能够迅速完成用户安装好的APP的升级,在某种意义上提升了用户的体验,可是开发者的开发方式也会变得比较“绕”,开发成本增长了很多,为了保证兼容性也会放弃使用Android的一些没法在动态加载框架上使用的功能,因此体验每每比不上“正统”的Android开发方式。
缺乏了Google Play的约束,一些Android APP就变得肆意妄为了,这一点在BAT系中显得格外明显。常驻内存就接受到服务器的推送信息的成功率就比较高了,用户明明关了一些APP,可是它们就不想退出,就算咱们手动关闭了它们,一旦从新启动、网络变化等,它们就又从新启动了,占着原本就珍贵的手机内存,很快就不够用了,这也是Android卡顿的一大缘由。“百度全家桶”你怕不怕?,一旦安装了百度家族启动的一个APP,就会偷偷帮你安装上全家族的APP,就算是我这种作Android研发的都常常中招,不用说普通的用户了。更可恨的是这些APP还会互相唤醒,Andriod Lollipop以后你能够完全关闭一个APP,除非你手动启动它不然它没法自启动,可是家族APP之间互相唤醒使得这成为了可能,“绿色守护”等后台清理神器在“互相唤醒”大法之下也没辙了。
Android原生与H5界面交互的框架已经很成熟了,许多中大型的APP的有H5的界面,特别是淘宝、天猫、京东这种购物类的,这些APP有大量和时间相关的活动,在节日以前开发一个新版本的APP再发布到应用市场显得太蠢了,H5网页这种随时能够更新在线内容的技术最适合这种活动了。然而H5界面的性能在仍是肛不过原生界面,特别是各类黑科技附身的Lollipop以后的时代,特别是当一个界面有H5的东西也有原生的东西那就更加糟糕了。此外,国内设计师都喜欢把Android的美术图设计得和IOS同样,这里不讨论这样作的缘由,然而结果就是Android的开发须要使用大量的自定义View,这样一来,许多系统自带控件的加速效果(特别是当用到系统公共资源的时候)就没有什么卵用了,并且每每这些自定义View都有或多或少的Bug,可能设计得不合理,也可能有内存泄露,这些都会影响APP的性能。
上面说的客观缘由除了因为Android的碎片化问题以外,其实有很大部分是开发者有意为之,可是我相信这并非Android开发的责任,咱们是都是清白的,都是无奈的,错的不是咱们,是世界啊!╮( ̄▽ ̄")╭。也不是产品经理的锅,而是大环境造就的。国内互联网的竞争堪比电商,不这么作,不抢占用户的手机的话根本就没法生存,就算百度不去作,阿里也会去……因此勉强能够把这些归类为客观因素。可是瞎BB了这么多,都不是我想说的主要内容,我想许多人都不感兴趣,我只是一时来兴致了敲了这么多字,感受若是不贴出来的话不就亏了嘛。
…………
……
…
既然你都看到这了,顺便把主观缘由部分也看完吧_(-ω-`_)⌒)_。
主观缘由主要是因为开发过程当中的过错致使的,整体上来讲大体有如下几方面的缘由
APP要流畅的话就好让它保持高度相应,CPU要能及时响应UI线程的操做。不过不可能把全部非UI的工做通通扔到异步任务里面去,有时候一些工做直接在UI线程搞会很是方便,并且太多后台线程也会形成大量的性能开销。这是一个矛盾,这时候就须要成熟的异步任务框架咯,若是这个框架没写好的话,就可能致使后台任务混乱,产生多余的线程开销,UI线程得不到及时的响应,更甚,若是有异步任务形成内存泄露,内存不够用很快就卡顿了,甚至直接OOM嗝屁了。
内存是很是宝贵的,再多也不嫌多。因此当一个对象离开他的做用域后,咱们必定马上回收它占有的内存,最理想的状态是对每个对象都能作到这样,若是有一个对象作不到,就说明他泄露了。Android中,Activity对象以及Bitmap的像素数据每每占用很是大的内存,若是这二者发生泄漏会致使可用内存急剧减小,那卡顿则就没法避免。此外,即便没有严重的内存泄露,可是频繁建立对象和回收对象的话,会引起虚拟机频繁的GC,GC占用比较大的资源开销,一样也可能会致使卡顿。总的来讲,开发过程当中要对内存的使用保持敏感,知根知底。
设计师给出的同一张美术图能够有多张的布局实现,不一样方案之间的性能可能相差很远。ListView等列表控件的Adapter也有许多优化点,许多人容易疏忽。
这就不仅是Android领域的问题啦,某些特定的业务应该采用最优算法,把时间复杂度降到最低,尽可能避免指数级别的时间复杂度,尽可能以空间换时间,必要的时候使用Native库来提升算法。
一开始我也提到了,其实性能调优涉及到多方面的工做,好比一些静态的网络资源要作好缓存不要重复请求;频繁数据库操做的话最好使用异步任务,SQLite默认实在UI线程直接操做数据库的;使用反射也会比较性能,不过反射有时候确实挺方便的,特别是项目庞大的时候,这个看取舍;过分使用“设计模式”也会有额外的开销,设计意味着更多接口和多态,业务跑起来须要额外的空间和时间;尽可能不要开多进程,进程之间的通信比同一进程之间的互调消耗的性能很是多,通常项目只要一个进程就够了,有推送的能够多一个推送进程;此外,不限制与Android客户端开发,H五、服务器的优化也能提升APP的性能。
这个在后面的具体分析中,再结合实际遇到的问题一块儿介绍吧。
关于性能优化的技术点,欢迎你们到这个日志里补充:[收集向] Android 性能调优的技术点