为什么需要开发规范
- 一个软件的生命周期中,80%的花费用于维护
- 没办法保证开发人员和维护人员是同一个人
- 如果将源码作为作品发布,他不但是给机器理解的,更需要给人理解
- 开发规范可以改善软件的可理解性,并保持软件的清晰无误
原则
- 编码前想清楚代码的逻辑结构,必要时可借助图形图表来帮助思考
- 切勿简单的Copy-Paste编码
- 随手重构有“坏味道”的代码
- 保持代码的简单清晰
- 使用sdk提供的统一工具类,不要重复造轮子。比如,StringUtils、LogCatLog等。
格式布局
- 缩进排版,4个空格作为一个缩进的单位
- 行长度,尽量避免一行的长度超过120个字符
- 换行,当一个表达式无法在一行内书写时,可以依据如下规则断行:
- 在一个逗号后面断开
- 在一个操作符号前面断开
- 宁可选择高级别的断行,而非低级别的断行
- 新的一行应该与上一行同级别的表达式开头对齐
- 如果以上规则导致你的代码混乱或者使你的代码堆积在右边,就代之缩进2个单位(8空格)
- 语句块的“{”不要另起新行
- 尽量使用圆括号来避免运算符优先级问题
例如:
private static synchronized horkingLongMethodName(int anArg,
Object anotherArg, String yetAnotherArg,
Object andStillAnother) {
...
}
注释
- 代码本身应该包含软件的大部分信息,通过代码便可以理解它的意思
- 好的注释为了说明软件的意图或者总结程序的功能,而不是简单的重复代码,他解释的是“为什么”而不是“是什么”
- 对使人困惑的代码进行重写而不是注释
- 对过期的注释要进行更新修正,删除冗余和自相矛盾的注释,确保注释清晰正确
- 对以下情况必须要有注释:
- 每个java文件的头部,标明@author,方便联系。可与该java文件的主要类的功能说明,合并到一个注释块中。
- 每个类的功能(特别是public类)
- 方法的功能(存取方法除外,特别是public方法)
- 类变量的功能
- 冗长或复杂的控制结构
- 输入参数的特殊限制
- 去掉自动生成的“// TODO Auto-generated method stub”
- 待改进的代码用“//FIXME:”进行注释
例如:
/**
* @author sanping.li
* AST节点接口
*
*/
public interface Node {
/**
* 节点创建完成之后,准备添加子节点
*/
public void open();
...
}
命名
- 命名采用驼峰命名法
- 变量名、函数名和控件View id,首字母小写,后面单词的首字母大写
- 常量名全部大写
- 类名首字母大写
- 包名全部小写
- 命名是为了区分标识,如果相同级别所有的元素都有相同的名字“装饰”,就可以去掉(比如布局文件,类名前面的Alipay)
- 变量名要准确描述变量的含义,不要使用没意义的名字,不要随意使用缩写,特别是有歧义的缩写
- 命名不要过长也不要过短,不要超过4个单词
例如:
package com.alipay.android.core;//包
public class ActivityShell extends RootActivity {//类
private int mType;//变量
private boolean checkRequisite();//方法
public static final int STATE_NOMARL = 0;//常量
android:id="@+id/titleDivider"
变量
- 推荐每行只声明一个变量
- 不要将不同类型的变量声明放在一块
- 变量声明可以使用制表符对齐
- 显式的声明变量的作用域
- 尽量缩小变量的作用域,加强封装性。若没足够理由,不要使用public类的变量
例如:
private int mState;
private String mName;
private Map<String,Object> mCache;
语句
- 每行只包含一条语句
- 避免在一个语句中给多个变量赋值
- 语句块尽管只有一行语句,也尽量加上“{}”
- switch语句的每个case后面需要有break或者return语句
- switch语句必须要default语句
- 禁止死循环,除非确有必要,并能保证万无一失。否则,要加上最大循环数的控制。
例如:
if (mType == TYPE_XML){
...
}
switch (mState) {
case STATE_PAUSE:
...
break;
case STATE_INSTALLING:
...
break;
default:
throw new Exception("error msg");
}
方法
- 每个方法只做一件事并做好
- 每个方法的长度不要超过47行
- 方法的参数个数尽量少,不要超过5个
- 逻辑嵌套层次不要大于三层
- 一个方法只有一个出口
例如:
public int doSomething(int arg1,int arg2){
int retVal = 0;
...
return retVal;
}
类
- 一个类不但要封装数据,还要封装操作
- 使用常量来代替“魔法数字”
- 每个类的长度不要超过1000行
- 不要使用对象来访问静态变量和方法
例如:
public class Sample{
private static final int TYPE_XML = 0;
...
Processor.parser(argument);//不要new Processor().parser(argument)访问静态方法和变量
...
if(mType == TYPE_XML){//用常量来替换“魔法数字”,而不是if(mType == 0){
}
包
- 包不要划分的过粗也不要过细
- 包的划分按段来区分功能及子功能的模块
异常处理
- 尽量减小try块的体积,不要嵌套try块。
- 捕获了异常就需要对它进行适当的处理,而不是丢弃,否则应该向上抛
- 在catch语句中尽可能指定具体的异常类型,必要时使用多个catch,不要试图处理所有可能出现的异常。
- 充分运用finally,保证所有资源都被正确释放
- 不要在finally中出现return语句
- 在异常处理模块中提供适量的错误原因信息,组织错误信息使其易于理解和阅读。
- 全面考虑可能出现的异常以及这些异常对执行流程的影响,不要使用异常来做流程控制。
- 异常捕获不是万能的,不要出现问题全套进来
例如:
try {
...
} catch (FileNotFoundException fe) {
Log.e(TAG,fe.getMessage());//组织错误信息
} catch (IOException ie) {
Log.e(TAG,ie.getMessage());//组织错误信息
} catch (Exception e){
...//不处理应该向上抛
} finally {
...
}
线程
- 必须给常驻线程起个名字,方便识别。
- 不允许在持有锁的时候调用Thread.sleep
资源
- 尽量使用资源而不是代码来完成功能
- 布局文件要尽量简洁,且模块清晰
- 尽量使用样式来控制布局元素的外观
- 字符常量要放到strings.xml
- 9png的四个区域最好画全
- 一定不要忘记关闭流
- 游标使用方切记关闭游标
性能
- 不要在主线程上执行任何 i/o、网络请求等耗时操作;这类操作都有可能造成UI 没有响应,产生ANR。
- 一个 当前显示界面的 Layout不能超过 80 个Views;(From Google I/O 2009 Sesstion Optimize layout)
- Layout的嵌套要尽可能的少;一个Page 的最深Layout 嵌套不要超过8个;可以做 Scroll 操作的Layout 嵌套深度 不能超过5个
生命周期
- 应用程序生命周期的对象关联的应该是Application Context
- Activity生命周期的数据关联的才是Activity Context
- 要考虑Activity被回收时候的数据保存和恢复,不单是Activity的数据还有Application的数据
- 不能在其他类里强引用Activity,如果需要必须在合适时机完成解绑,否则会导致Activity不能正常回收,造成资源泄露。
内存管理
- 同样的数据只保存一个副本
- 列表类的数据尽量使用AdapterView来展示
- 使用Adapter的时候注意convertView的处理,并可以考虑ViewHolder
- 尽量不要去处理(合成,拷贝)bitmap
- bitmap对象过多的时候考虑使用软引用
- 尽量使用android的activity而非view
- 尽量少用静态变量,否则需要显示的去释放它所占的内存
例如:
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
...//创建视图
}
...//做数据处理
}
安全
- 本地不应保存密码或用对称方式加密后的密码。
- 本地保存用户隐私数据应遵循相关规定。隐私数据包括用户姓名,手机号,身份证号,银行卡号,交易记录等
- 客户端输出的日志中应过滤掉敏感信息
- 客户端代码发布前必须混淆
接口兼容性
- 定义对外暴露接口的时候,需要考虑到接口的扩展,例如用k-v字符串代替不可扩展的结构体,预留扩展参数等。
- 不要尝试修改一个接口中对外公开的方法的定义(包括方法名、参数、返回值等)。如果有新功能需求,必须扩展出一个新的方法或者接口。这样才能处理好接口的兼容。
操作习惯
- 常格式化代码(eclipse使用ctrl+shift+F)
- 代码文件统一使用utf-8编码,请把eclipse的workspace设置utf-8。设置方法是,Preferences->General->Workspace
- 去除不必要的包导入(eclipse使用ctrl+o)以及不用的变量和方法
- 代码提交
- 提交代码前用版本控制工具查看所做的修改
- 提交代码前要先做update
- 提交代码的需要写备注,本次修改的详细信息,如果是fix bug,需要给出bug的headline或链接
- 不再需要的日志输出(如为了调试方便的日志),请及时删除掉,不要保留在正式代码中。
- 去除不必要的包导入(eclipse使用ctrl+o)以及不用的变量和方法