I. 网络相关

  • http头信息带Cache-Control域 确定缓存过期时间 防止重复请求
  • 直接用IP直连,不用域名,策略性跟新本地IP列表。 – DNS解析过程耗时在百毫秒左右,并且还有可能存在DNS劫持。
  • 图片、JS、CSS等静态资源,采用CDN(当然如果是使用7牛之类的服务就已经给你搭建布置好了)
  • 全局图片处理采用漏斗模型全局管控,所请求的图片大小最好依照业务大小提供/最大不超过屏幕分辨率需要,如果请求原图,也不要超过GL10.GL_MAX_TEXTURE_SIZE
  • 全局缩略图直接采用webp,在尽可能不损失图片质量的前提下,图片大小与png比缩小30% ~ 70%
  • 如果列表里的缩略图服务器处理好的小图,可以考虑直接在列表数据请求中,直接以base64在列表数据中直接带上图片(国内还比较少,海外有些这种做法,好像web端比较常见)
  • 轮询或者socket心跳采用系统AlarmManager提供的闹钟服务来做,保证在系统休眠的时候cpu可以得到休眠,在需要唤醒时可以唤醒(持有cpu唤醒锁)
  • 可以通过将零散的网路的请求打包进行一次操作,避免过多的无线信号引起电量消耗。

1. 传输数据格式选择

  • 如果是基本需要全量数据的,考虑使用Protobuffers (序列化反序列化性能高于json)
  • 如果传输回来的数据不需要全量读取,考虑使用Flatbuffers (序列化反序列化几乎不耗时,耗时是在读取对象时(就这一部分如果需要优化,可以参看Flatbuffer Use Optimize

2. 输入流

使用具有缓存策略的输入流

原 建议替换为
InputStream BufferedInputStream
Reader BufferedReader

II. 数据结构

如果已知大概需要多大,就直接给初始大小,减少扩容时额外开销。

1. List

ArrayList

里面就一数组,内存小,有序取值快,扩容效率低

LinkedList

里面就一双向链表,内存大,随机插入删除快,扩容效率高。

2. Hash

HashSet

里面就一个HashMap,用key对外存储,目的就是不允许重复元素。

ConcurrentHashMap

线程安全,采用细分锁,锁颗粒更小,并发性能更优

Collections.synchronizedMap

线程安全,采用当前对象作为锁,颗粒较大,并发性能较差。

3. Int作为Key的Map

针对该特性进行了优化,采用二分法查找,简单数组存储。

SparseArray、SparseBooleanArray、SparseIntArray。

III. 数据库相关

建多索引的原则: 哪个字段可以最快的减少查询结果,就把该字段放在最前面

无法使用索引的情况

  • 操作符BETWEEN、LIKE、OR
  • 表达式
  • CASE WHEN

不推荐

  • 不要设计出索引是其他索引的前缀(没有意义)
  • 更新时拒绝直接全量更新,要更新哪列就put哪列的数据
  • 如果最频繁的是更新与插入,别建很多索引 (原本表就很小就也没必要建)
  • 拒绝用大字符串创建索引
  • 避免建太多索引,查询时可能就不会选择最好的来执行

推荐

  • 多使用整型索引,效率远高于字符串索引
  • 搜索时使用SQL参数("?", parameter)代替字符串拼接(底层有特殊优化与缓存)
  • 查询需要多少就limit多少(如判断是否含有啥,就limit 1就行了嘛)
  • 如果出现很宽的列(如blob类型),考虑放在单独表中(在查询或者更新其他列数据时防止不必要的大数据i/o影响性能)

IV. JNI抉择

Android JVM相关知识,可参看: ART、Dalvik

Android JNI、NDK相关知识,可参看: NDK

JNI不一定显得更快,有些会更慢。

特点: 不用在虚拟机的框子下写代码

  • 可以调用更底层的高性能的代码库 – Good
  • 如果是Dalvik,将省去了由JIT编译期转为本地代码的这个步骤。 – Good
  • Java调用JNI的耗时较Java调用Java肯定更慢,虽然随着JDK版本的升级,差距已经越来越小(JDK1.6版本是5倍Java调用Java方法的耗时) – Bad
  • 内存不在Java Heap,没有OOM风险,有效减少gc。 – Good

一些重要的参数之类,也可以考虑放在Native层,保证安全性。参考: Android应用程序通用自动脱壳方法研究

V. 多进程抉择

360 17个进程: 360手机卫士 Android开发 InfoQ视频 总结

  • 充分独立,解耦部分
  • 大内存(如临时展示大量图片的Activity)、无法解决的crash、内存泄漏等问题,考虑通过独立进程解决
  • 独立于UI进程,需要在后台长期存活的服务(参看Android中线程、进程与组件的关系)
  • 非己方第三方库(无法保证稳定、性能等问题,并且独立组件),可考虑独立进程

最后,多进程存在的两个问题: 1. 由于进程间通讯或者首次调起进程的消耗等,带来的cpu、i/o等的资源竞争。2. 也许对于部分同事来说,会还有可读性问题吧,毕竟多了层IPC绕了点。

VI. UI层面

相关深入优化,可参看Android绘制布局相关

对于卡顿相关排查推荐参看: Android性能优化案例研究(上)与Android性能优化案例研究(下)

  • 减少不必要的不透明背景相互覆盖,减少重绘,因为GPU不得不一遍又一遍的画这些图层
  • 保证UI线程一次完整的绘制(measure、layout、draw)不超过16ms(60Hz),否则就会出现掉帧,卡顿的现象
  • 在UI线程中频繁的调度中,尽量少的对象创建,减少gc等。
  • 分步加载(减少任务颗粒)、预加载、异步加载(区别出耗时任务,采用异步加载)

VII. 库推荐

可以参考Falcon Pro作者的推荐: Falcon Pro 3如何完成独立开发演讲分析

1. 代码编写习惯

RxJava (响应式编程,代码更加简洁,异步处理更快快捷、异常处理更加彻底、数据管道理念)

相关了解可以参看: RxJava

2. 图片加载:

3. 网络底层库:

Okhttp: 默认gzip、缓存、安全等

4. 网络基层:

Retrofit: 非常好用的REST Client,结合RxJava简单API实现、类型安全,简单快捷

5. 数据库层:

Realm: 效率极高(Falcon Pro 3的作者Joaquim用了该库以后,所有数据库操作都放到了UI线程)(基于TightDB,底层C++闭源,Java层开源,简单使用,性能远高于SQLite等)

6. Crash上报:

Fabric: 全面的信息(新版本还支持JNI Crash获取和上报)、稳定的数据、及时的通知、强大的反混淆(其实在混淆后有上传mapping)

7. 内存泄漏自动化检测

LeakCanary: 自动化泄漏检测与分析 ( 可以看看这个LeakCanary使用总结与Leakcanary Square的一款Android/Java内存泄漏检测工具)

8. 其他

VIII. 内存泄漏相关

  • 无法解决的泄漏(如系统底层引起的)移至独立进程(如2.x机器存在webview的内存泄漏)
  • 大图片资源/全屏图片资源,要不放在assets下,要不放在nodpi下,要不都带,否则缩放会带来额外耗时与内存问题
  • 4.x在AndroidManifest中配置largeHeap=true,一般dvm heep最大值可增大50%以上。
  • 在Activity#onDestory以后,遍历所有View,干掉所有View可能的引用(通常泄漏一个Activity,连带泄漏其上的View,然后就泄漏了大于全屏图片的内存)。
  • 万金油: 静态化内部类,使用WeakReference引用外部类,防止内部类长期存在,泄漏了外部类的问题。

图片Decode

  • 全局统一BitmapFactory#decode出口,捕获此处decode oom,控制长宽(小于屏幕分辨率大小 )
  • 如果采用RGB_8888 oom了,尝试RGB_565(相比内存小一半以上(wh2(bytes)))
  • 如果还考虑2.x机器的话,设置BitmapFactory#options的InNativeAlloc参数为true,此时decode的内存不会上报到dvm中,便不会oom。

IX. 编译与发布

  • 考虑采用DexGuard,或ProGuard结合相关资源混淆来提高安全与包大小,参考: DexGuard、Proguard、Multi-dex
  • 结合Gradle、Gitlab-CI 与Slack(Incoming WebHooks),快速实现,打相关git上打相关Tag,自动编相关包通知Slack。
  • 结合Gitlab-CI与Slack(Incoming WebHooks),快速实现,所有的push,Slack快速获知。
  • 结合Gradle中Android提供的productFlavors参数,定义不同的variations,快速批量打渠道包

X. 其他

  • final能用就用(高效: 编译器在调用final方法时,会转入内嵌机制)
  • 懒预加载,如简单的ListView、RecyclerView等滑动列表控件,停留在当前页面的时候,可以考虑直接预加载下个页面所需图片
  • 智能预加载,通过权重等方式结合业务层面,分析出哪些更有可能被用户浏览使用,然后再在某个可能的时刻进行预加载。如,进入朋友圈之前通过用户行为,智能预加载部分原图。
  • 做好有损体验的准备,在一些无法避免的问题面前做好有损体验(如,非UI进程crash,可以自己解决就不要让用户感知,或者UI进程crash了,做好场景恢复)
  • 做好各项有效监控:crash(注意还有JNI的)、anr(定期扫描文件)、掉帧(绘制监控、activity生命周期监控等)、异常状态监控(本地Log根据需要不同级别打Log并选择性上报监控)等
  • 文件存储推荐放在/sdcard/Android/data/[package name]/里(在应用卸载时,会随即删除)(Context#getExternalFilesDir()),而非/sdcard/根目录建文件夹(节操问题)
  • 通过gradle的shrinkResources与minifyEnabled参数可以简单快速的在编包的时候自动删除无用资源
  • 由于resources.arsc在api8以后,aapt中默认采用UTF-8编码,导致资源中大都是中文的resources.arsc相比采用UTF-16编码更大,此时,可以考虑aapt中指定使用UTF-16
  • 谷歌建议,大于10M的大型应用考虑安装到SD卡上: App Install Location
  • 当然运维也是一方面: Optimize Your App
  • 在已知并且不需要栈数据的情况下,就没有必要需要使用异常,或创建Throwable生成栈快照是一项耗时的工作。

Android开发优化宝典的更多相关文章

  1. [Android] Android开发优化之——使用软引用和弱引用

      Java从JDK1.2版本开始,就把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引用和虚引用. 这里重点介绍一下软引用和弱引用. ...

  2. Android开发优化之——对Bitmap的内存优化

    http://blog.csdn.net/arui319/article/details/7953690 在Android应用里,最耗费内存的就是图片资源.而且在Android系统中,读取位图Bitm ...

  3. Android开发优化之——使用软引用和弱引用

    Java从JDK1.2版本开始,就把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引用和虚引用. 这里重点介绍一下软引用和弱引用. 如果 ...

  4. [原]Android开发优化-Adapter优化

    ListView作为Android开发中使用频率最高的一个控件,保证ListView的流畅运行,对用户体验的提高至关重要.Adapter是ListView和数据源之间的中间人,当每条数据进入可见区时, ...

  5. [Android] Android开发优化之——对界面UI的优化(2)

    在Android应用开发过程中,屏幕上控件的布局代码和程序的逻辑代码通常是分开的.界面的布局代码是放在一个独立的xml文件中的,这个文件里面是树型组织的,控制着页面的布局.通常,在这个页面中会用到很多 ...

  6. [Android] Android开发优化之——对界面UI的优化(1)

    在Android应用开发过程中,屏幕上控件的布局代码和程序的逻辑代码通常是分开的.界面的布局代码是放在一个独立的xml文件中的,这个文件里面是树型组织的,控制着页面的布局.通常,在这个页面中会用到很多 ...

  7. [Android] Android开发优化之——从代码角度进行优化

    通常我们写程序,都是在项目计划的压力下完成的,此时完成的代码可以完成具体业务逻辑,但是性能不一定是最优化的.一般来说,优秀的程序员在写完代码之后都会不断的对代码进行重构.重构的好处有很多,其中一点,就 ...

  8. 解析Android开发优化之:从代码角度进行优化的技巧

    下面我们就从几个方面来了解Android开发过程中的代码优化,需要的朋友参考下   通常我们写程序,都是在项目计划的压力下完成的,此时完成的代码可以完成具体业务逻辑,但是性能不一定是最优化的.一般来说 ...

  9. Android开发优化之——从代码角度进行优化

    通常我们写程序,都是在项目计划的压力下完成的,此时完成的代码可以完成具体业务逻 辑,但是性能不一定是最优化的.一般来说,优秀的程序员在写完代码之后都会不断的对代码进行重构.重构的好处有很多,其中一点, ...

随机推荐

  1. 关于分区技术的索引 index

    关于分区技术---索引 Index 一.   分区索引分类: 本地前缀分区索引(local prefixedpartitioned index) 全局分区索引(global partitionedin ...

  2. 七、mysql索引选择

    .myisam,bdb,innodb,memory 单表至少支持16个索引 .create index id_index on emp (id) 为emp表创建一个名为id_index的id字段的索引 ...

  3. JS禁用浏览器退格键

    我们在真实的项目开发中经常会使用JS 对键盘上的一些按键进行禁用,常见的比如说退格键(backspace/ 后退键),我在一个项目中就遇到过在页面编辑的时候禁用掉退格键,因为退格键会发生页面后退,代码 ...

  4. WdatePicker 设置开始时间和结束时间

    开始时间: <input type="text" placeholder=" -请选择- " readonly="readonly" ...

  5. Elasticsearch搜索类型(query type)详解

    关于我,邯郸人. 对这类话题感兴趣?欢迎发送邮件至donlianli@126.com 请支持原创http://www.cnblogs.com/donlianli/p/3857500.html    e ...

  6. C#中Thread.sleep()

    我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题:1.假设现在是 2008-4-7 12:00:00.000,如果我调 ...

  7. 1031: [JSOI2007]字符加密Cipher - BZOJ

    Description喜欢钻研问题的JS 同学,最近又迷上了对加密方法的思考.一天,他突然想出了一种他认为是终极的加密办法:把需要加密的信息排成一圈,显然,它们有很多种不同的读法.例如下图,可以读作: ...

  8. c++ 容器类

    #include <iostream> #include <vector> #include <list> #include <map> using n ...

  9. Delphi逆向

    Delphi反汇编内部字符串处理函数/过程不完全列表 名称 参数 返回值 作用 等价形式 / 备注 _PStrCat EAX :目标字符串 EDX :源字符串 EAX 连接两个 Pascal 字符串 ...

  10. ural 1221

    本来就是个很水的题  就是枚举起点长度然后直接判断就行了   但是比赛的时候写了个大bug 还找不出来     自己太水了 #include <cstdio> #include <c ...