Android代码规范
2019-05-16 本文已影响0人
董江鹏
大多时候我们面对的问题,并不是性能问题,而是可读性的问题。比如我们的代码如果有错误、有性能问题,只要结构清晰,通俗易懂,别人就很快能代为处理掉,重要的不是写多么XX的代码,而是写人类可读的代码。此文将主要就代码可读性给出建议,并提供一下性能检测方法。
通用部分
- 一个函数不要超过40行
- 这是我经常推荐给别人,而且自己坚持践行的方法。为什么是40行?很简单,因为屏幕最多能显示40行左右,40行以内的函数我不用鼠标就能看清这个函数的全貌,输入输出、局部变量,都不用花精力去记忆,可以集中精力阅读不用分心。
- 短函数还有个好处是,我们可以再短时间内判断这个函数有没有问题,明显没有问题的函数就不用仔细看了。
- 短函数在很多时候可以代替注释,使用可读的函数名比注释重要的多。有些帮助函数也许就只有两行,然而它们却能大大简化主要函数里面的逻辑。
- 重构方法参考《重构 改善既有代码的设计》
- 不要出现魔数
- 魔数是指代码里没有任何解释的数字。比如你和服务端约定的状态码,只有你知他知,其它人都不知道,没人看得懂,魔数必须用可读的常量声明。
- 使用有意义的变量名并做好分类
- 不要使用只有自己能理解的简称、缩写
- 参考《阿里巴巴Java开发手册》和《阿里巴巴Android开发手册》
- 不要重用局部变量
- 可读性不好
- 大概率会出错
- 不方便重构
- 不要省略花括号
- 编程语言都允许if、for之类的函数里只有一句的话可以不加括号,但不要这样做。
- 用括号替代运算符优先级
- 几乎没人能记忆所有的运算符优先级,也没有必要,加上括号通俗易懂。
- 处理不了的异常直接抛给使用者,不要返回空
- 能处理的异常做好处理或做好日志输出
- 不能处理的异常直接抛给使用者,不要返回空
- commit message不要只写一两个单词
- commit message虽然与代码无关,但是清晰的message可以方便大家排查问题。遇到问题可以先排除明显没有问题的提交。
- 区分提交类型(新功能、修补bug、重构)
- 这里有教程
- 尽量不要使用位运算
- 只会让代码更难读
Android/Java部分
-
不直接使用Thread
考虑到用户界面的生命周期,大量使用线程池会导致界面销毁的时候线程任务无法细粒度地取消,可能会导致CPU被大量无用任务占用,影响后续工作的性能,考虑到这种情况,推荐在界面相关任务中使用HandlerThread调度
- 使用线程池或HandlerThread
- 控制线程优先级为后台线程
- 区分计算密集型任务和io密集型任务,使用不同的线程池
- 理解SharedPreference
- 提前加载(getSharedPreference)可以减少后面读取value的时间
- 如果不涉及多进程,并且在onDestory生命周期之前,请使用apply()
- 同一个Editor多个修改操作可以在追加在前一个修改后面,一次提交
- 不要用来做进程间通信
- 如果由于历史原因,上面一条没法做到的话,至少要保证不涉及多进程的不加MODE_MULTI_PROCESS标记,这个标志会使内存缓存无效,影响性能
- 理解Handler
- 不要手动调用loop(),可以用HandlerThread替代
- new Handler需要明确指定线程looper
- 不要在主线程执行耗时任务
- 理解主线程的范围,四大组件生命周期函数均在主线程执行,不要在Service和BroadcastReceiver里执行耗时任务
- 用systrace测一下自己写的函数的耗时情况,这里是教程
- 用细粒度的锁
- 尽量不要对整个函数加锁
- 无法编辑的工具类尽量使用无锁结构,把控制权交给使用者
- 使用读写锁区分读多写少的场景,提高读取性能
- 用HashMap替换循环查找List
- 空间换时间
- 预防OutOfMemory和内存泄露
- 长生命周期对象持有的大量可递增数据引用,用SoftReference或LruCache防止OutOfMemory
- 长生命周期对象需要持有短生命周期对象的引用,用WeakReference防止内存泄露
- 不要手动解析json、xml
- 使用Gson之类的工具
- 数据存取、业务逻辑、界面显示分离(MVC、MVP)
- 通过短函数做数据的输入输出,每次只做一件事,方便替换优化数据源
- 使用空Activity,只用Fragment显示界面,将Controller或者Presenter独立出来,方便替换优化界面实现
- 这里是官方示例代码
- 非定时任务尽量不用Message
- 主线程looper可以在任何地方轻松拿到,Looper.getMainLooper()
- 搜索Message会打断正常的阅读流程,优先将代码函数化
- 不要传递json中间对象
- 包括但不限于JSONObject、JSONArray
- 用之前提前解析为业务对象