规范及注意
|
解释及说明
|
打开了资源,要记得关闭资源。要尽量晚地获取,尽量早地释放。 |
|
使用AsyncTask、线程、IntentService或自定义后台服务来处理脏活 |
|
确保你设计的布局简单、简练和浅层 |
setContentView()几乎占用了从onCreate()开始到onResume()结束之间所有时间的99% |
减少创建对象的数量。消除不必要的对象,或者推迟创建对象 |
|
采用嵌套的线性布局会深化布局层次,从而导致布局和按键处理变慢。 |
|
减少布局层次的技巧是用<merge />标签来合并布局。 如果你的布局的最上层也是一个FrameLayout,就可以用<merge />标签代替它,减少一层布局 |
|
重用布局使用<include /> 标签 |
|
ViewStub推迟初始化是个方便的技术,可以推迟实例化,提高性能,还可能会节省内存 |
|
让你应用程序的资源适合目标设备 |
如果你添加了可利用的庞大图像资源,需要装入和调整大小,就无法有效地使用其他的应用程序资源 |
从外部获取数据(Dex, Html, Apk)时,一定要校验数据可靠性,防止数据被第三方而已篡改 |
|
manifest中activity节点若非必要,不要添加intent-filter(添加就意味着可以被外部其他应用或进程启动) |
|
从安全角度不要使用Broadcast,广播的传播性是不可控的,而且容易被劫持,信息被截取。(应用内广播可以参考supportV4包中的LocalBroadcastManager。) |
|
敏感信息输入使用自定义键盘 |
|
在代码中小心使用Runtime.exec方法,尤其是运行参数由用户输入产生时,一定要验证参数的合理合法性 |
|
内部组件从intent获取数据时,注意判断null情况 |
|
Webview禁止使用savePassword(true)方法 |
|
不要自己拼接SQL,防止sql注入攻击 |
|
不要使用Android默认的AES加密 |
|
谨慎使用service,service无job第一时间关闭service,让service在不必要的情况下运行是内存管理上最大的错误之一 |
service启动之后,系统会一直保持service的运行,service占用的内存会一直无法释放 |
只要当前屏幕显示需要时,才将Bitmap放入内存,如果原Bitmap的分辨率偏高,就把它缩写 |
一定要记住增加Bitmap的分辨率会导致内存占用呈指数上涨 |
使用Android优化过的集合,比如: SparseArray, SparseBooleanArray,andLongSparseArray |
Java中的HashMap在内存方面相当低效,每个KV对都需要分配一个Map.Entry来存放,向HashMap中存放一个Entry会分配一个额外的Entry,占用大概32 字节 |
避免使用枚举 |
Enum比常量要多占用2倍的内存 |
谨慎使用抽象类和抽象方法 |
通常抽象被看做是一种好的编程习惯,但是抽象有很大的开销:需要执行更多的代码、执行更长时间、占用更多内存。 |
使用nano protobufs序列化数据 |
pb是google的平台独立、语言独立、可扩展的序列化工具;相对于XML更小、更快、更简单。 |
避免使用依赖注入框架 |
依赖注入框架能简化代码,为测试、修改配置等提供很方便的环境。但是,但这些框架会有很多扫面注解的初始化,这些工作很耗时并且占用大量内存。 |
谨慎使用第三方类库 |
大部分第三方类库不是针对移动客户端设计,如果在移动设备上使用并不高效。至少在使用前,你应该对这些类库进行优化。 |
使用ProGuard清除无用代码 |
|
使用 zipalign对apk进字节对齐,不然会耗费更多内存 |
|
多进程需谨慎使用-会增加内存占用,大部分app不需要多进程 |
一个什么都不运行的空进程大概占用1.4MB内存,一个只运行了一个非常非常简单的界面的进程会占用4M内存 |
在内存紧张时释放内存 |
当设备的内存变少是,onTrimMemeory(int)方法会被调用 |
UI渲染程序要快速,避免卡顿产生 |
Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成 |
避免Overdraw(过度绘制),避免屏幕上的某个像素在同一帧的时间内被绘制了多次。 |
会浪费大量的CPU以及GPU资源,可以在开发者选项,打开Show GPU Overdraw的选项,可以观察UI上的Overdraw情况。 |
避免瞬间产生大量的对象 |
会严重占用Young Generation的内存区域,当达到阀值,剩余空间不够的时候,也会触发GC,GC发生的时候,所有的线程都是暂停状态的 |
避免在for循环里面分配对象占用内存,将trycatch 块移出循环 |
|
避免在onDraw方法里面执行复杂的操作,避免创建对象 |
|
尽量减少唤醒屏幕的次数与持续的时间,合理使用WakeLock来处理唤醒的问题 |
|
某些非必须马上执行的操作,例如上传歌曲,图片处理等,可以等到设备处于充电状态或者电量充足的时候才进行 |
平均只有30%左右的电量是被程序最核心的方法例如绘制图片,摆放布局等等所使用掉的,剩下的70%左右的电量是被上报数据,检查位置信息,定时检索后台广告信息所使用掉的。 |
把零散的网络请求打包进行一次操作,避免过多的无线信号引起的电量消耗 |
|
触发闹钟的时间不必过度精确; 尽量使用setInexactRepeating()方法替代setRepeating()方法 |
使用setInexactRepeating()时,Android系统会集中多个应用的重复闹钟同步请求,并一起触发它们。这可以减少系统将设备唤醒的总次数,以此减少电量消耗 |
尽量避免让闹钟基于时钟时间,尽可能使用ELAPSED_REALTIME |
|
如果方法不访问对象的字段,可以选择Static而不是Virtual |
方法是static类型的,这样方法调用将快15%-20% |
进本类型和String类型的常量声明为Static Final |
类初始化时若引用了静态final常量不再需要执行clinit()方法,常量已直接使用到dex文件里 |
避免内部的Getters/Setters |
C++或者Java和C#中推荐使用方法封装变量的访问,通过内联技术可以优化变量的访问速度。但是Android中方法调用时比较耗费资源的,因此对外部类可以通过方法调用范文属性,但是类的内部可以直接使用属性。 |
使用增强的for循环for-each,尽量避免使用Iterator来执行遍历操作 |
for(Object a : arrays)方式3X倍快于Iterable和arrays.get(index)方式遍历 |
使用包级访问而不是内部类的私有访问,但在公开的API中你不能这样做 |
|
避免使用float类型 |
float类型的数据存取速度是int类型的一半,尽量优先采用int类型 |
使用库函数 |
系统函数有时可以替代第三方库,并且还有汇编级别的优化,他们通常比带有JIT的Java编译出来的代码更高效 |
谨慎使用native函数 |
JIT不能在这种情况下做优化,收集资源困难,不同平台不同代码 |
合理的利用充电、电量不足、联网等事件停止或执行响应的耗性能操作 |
Android5.0提供了JobScheduler实现此能力 |
降低网络操作 |
网络操作相对来说是比较耗电的行为,激活瞬间,发送数据的瞬间,接收数据的瞬间都有很大的电量消耗 |
尽量使用Android平台提供的既有运动数据,而不是自己去实现监听采集数据 |
|
在Activity不需要监听某些Sensor数据的时候需要尽快释放监听注册 |
|
可以针对Sensor的数据做批量处理,待数据累积一定次数或者某个程度的时候才更新到UI上 |
|
为了确保所有的对象能够正确被释放,我们需要保证加入对象池的对象和其他外部对象没有互相引用的关系 |
|
要注意LRU Cache中被淘汰对象的回收,否者会引起严重的内存泄露 |
|
使用Lint扫描代码 |
|
开启StrickMode检测性能 |
|
尽量减少PNG图片的大小是Android里面很重要的一条规范 |
PNG能够提供更加清晰无损的图片,JPEG就可以达到视觉效果的,可以考虑采用JPEG即可,Webp,它是由Google推出的一种既保留png格式的优点,又能够减少图片大小的一种新型图片格式 |
对bitmap做缩放的意义很明显,提示显示性能,避免分配不必要的内存 |
Android提供了现成的bitmap缩放的API,叫做createScaledBitmap(),使用这个方法可以获取到一张经过缩放的图片 |
使用inBitmap属性可以告知Bitmap解码器去尝试使用已经存在的内存区域 |
新解码的bitmap会尝试去使用之前那张bitmap在heap中所占据的pixel data内存区域,而不是去问内存重新申请一块区域来存放bitmap |
Android4.4前的系统使用webview会出现ashmem的内存泄露,另起一个新的进程来启动webview的activity,activity销毁的时候,调用System.exit(0),退出进程,彻底释放内存 |
|
减少使用反射机制,如果一定要使用,看是否可能增加一层缓存 |
|
对传输数据根据业务情况压缩 |
|
千万不要用Class.getResrouceAsStream(),正确使用context.getResource() |
本身android在启动过程当中就会解析assert文件放到相应的map里,采用这种方式则会导致对所有class进行搜索并找到相应的类,加上android所有代码是打在一个apk里,则搜索的速度则相当慢 |
避免不需要的instanceof操作 |
|
当复制数组时使用System.arraycop方法 |
|
在进行数据库连接和网络连接时使用连接池 |
|
尽量使用基本数据类型代替对象 |
|
可以重写Activity的onNewIntent()来处理Activity创建后得到新的Intent场景 |
|
可以通过Package Manager的setComponentEnableSetting启动停止Manifest里的Receiver/activity/service,已减少不必要的开销 |
|
Handler类的定义应该是static的,否则容易产生内存泄露 |
如果Handler是个内部类,那 么它也会保持它所在的外部类的引用。为了避免泄露这个外部类,应该将Handler声明为static嵌套类,并且使用对外部类的弱应用。 |
快速异步保存场景使用Shared Preference.Editor.apply(),commit是同步保存 |
|
考虑效率因此,android的系统设计使得在任何时候都没有必要手动关闭数据库。 |
如果系统需要额外的资源,应用程序将会关闭,与其关联的数据库也会关闭 |
数据库查询使用Cursor注意要异步查询,并在使用后关闭,防止内存泄露 |
|
在Activity和Fragement里加载耗时数据使用LoaderManager异步加载 |
|
start方式启动Service导致服务一直存在比较耗费资源,bind方式可以使Service随Activity启动和终止,并提供方便的交互接口 |
|
尽量为每一个view设置contentDescription属性 |
语音工具可直接朗读 |
使用Passive Location Provider可降低定位能耗,适合后台读取位置信息 |
当且仅当其他应用请求位置更新时此Provider才会收到位置更新 |
使用Intent.resolveActivity(getPackageManager()) != null判断是否有应用处理intent |
避免没有处理的应用时crash |
避免直接加载超清图片到内存,通过缩放decodeResource技术加载使用平台显示分辨率即可 |
每个应用一般最大占用16M内存,超过会造成crash |
onPause()、 onStop()、onDestroy()方法中需要适当的释放资源 |
|
使用网络前最好检测可用性和网络类型,大数据最好在vifi下上传下载 |
|
尽量避免Polling方式轮训,可以使用长链接推送框架替代,即使必须使用考虑用最低的频率 |
|
不要在onDraw()方法里创建对象 |
可能会导致内存垃圾回收而造成卡顿 |
如果你的方法是返回string并且返回值会被append到一个StringBuffer上,请调整设计,避免创建临时存在在对象 |
避免创建不必要的短时间存在的对象,减少内存使用 |
int数组比Integer数组要节省资源,两个一维的数据比一个二维数组要节省资源 |
|
通过一个对象同时存储对象A和B不如分别通过两个数组存储A和B性能好,当然如果封装A和B是为了其他地方更好的引用那么可以忽略这部分影响 |
|
内部类访问外部类属性时,内部类尽量是包访问权限而不是Private。 |
private的内部类访问外部类的private属性时,通常认为不合法,但VM会自动添加静态方法实现能够访问 |
没有JIT时访问接口的方法比直接访问精确类型的方法性能好,有JIT时基本没差别 |
|
Traceview分析时会禁止JIT,容易导致执行时间分析的不准确,多耗费的时间可能因为JIT编译而优化掉 |
|
性能优化前请确保你遇到了性能问题,并且你可以测量性能优化的效果 |
|
layout嵌套场景使用layout_weight属性会很耗费性能,在使用ListView和GridView时更要注意 |
每一个子节点都要计算两次来计算布局空间 |