自用Android编码规范,持续更新
界面规范
drawable
- selector 类
命名规则:selector_{模块}_{控件}_{属性}
文字和背景同时存在 selector 时,示例: selector_login_btn_bg、selector_login_btn_text
仅文字或者背景可缩写为:selector_login_btn
通用:selector_btn
- shape 类
命名规则:drawable_{模块}_{控件}_{状态}
示例: drawable_login_btn_pressed、drawable_login_btn_normal
layout
Android 官方规范
命名规则:{组件}_{模块}_{业务}
示例:
activity_user_login
fragment_user_login
dialog_user_login
自定义view: layout_title
ListView的item: item_account
mipmap
命名规则:{模块}_{业务}_{组件}_{状态}
示例:
user_login_btn_pressed
user_login_btn_normal
anim
命名规则:anim_{模块}_{业务}_{组件}_{动画}_{方向}
示例:
anim_login_btn_top_in
通用:
anim_fade_in
dimens
命名规则:yh_dp_{具体值}、yh_sp_{具体值}
示例:
yh_dp_1
yh_dp_10
yh_sp_10
color
命名规则:yh_color_{具体颜色值}
示例:
yh_color_white
yh_color_red
yh_color_ff12ab
控件缩写
控件 | 缩写 |
---|---|
ImageView | iv |
Button | btn |
TextView | tv |
CheckBox | cb |
RadioButton | rb |
EditText | et |
ScollView | sv |
ListView | lv |
LinearLayout | ll |
RelativeLayout | rl |
ConstraintLayout | cl |
DatePicker | date_picker |
ProgressBar | progress_bar |
设计原则
- Single Responsibility Principle,简写为 SRP,单一职责原则
- Open Closed Principle,简写为 OCP,开闭原则
- Liskov Substitution Principle,缩写为 LSP,里式替换原则
- Interface Segregation Principle,缩写为 ISP,接口隔离原则
- Dependency Inversion Principle,缩写为 DIP,依赖倒置原则
- Keep It Simple and Stupid, 简写为 KISS,尽量保持简单
- You Ain’t Gonna Need It,简写 YAGNI,你不会需要它
- Aspect Oriented Programming,缩写 AOP,面向切面编程
- Inversion of Control,缩写为 IoC,控制反转
- Dependency Injection,简称 DI,依赖注入
命名风格
- 不以下划线或者美元符号开头或者结束
- 类名 UpperCamelCase
- 包名统一使用小写
- 禁止使用拼音命名
- 禁止不规范的缩写
- 多个参数逗号后需要加空格
- 成员变量 m 前缀开头,代表 member,示例:mNum、mUserService
- Java代码控件引用正序,如:mLoginBtn、mMainActivity
- 静态变量 s 前缀开头, 代表 static,如:sInstance
- 方法、参数名等统一采用 lowerCamelCase 风格,示例:loginManager
- 常量命名使用全大写,单词间用下划线分割,如:CODE_SUCCESS、REQUEST_CODE_LOGIN
- 包名 util 类名 utils,示例:LogUtils设计模式体现在名字中,如: UserProxy
- 获取单个对象使用get前缀,如:getAccount
- 获取多个对象 list 前缀,如:listAccounts
- 统计个数 count 前缀
- 插入 save
- 修改 update
- 不要使用一个常量类维护所有常量,要按常量功能进行归类
- 提交之前,一定要按 ctrl + alt + L 格式化代码
常量定义
-
不允许任何硬编码
反例:
String username = "user_" + userId;
-
在 long 或者 Long 赋值时,使用大写的 L
-
不要一个常量类维护所有常量,按功能归类、分开维护
-
常量的复用层次有五层:跨应用共享常量、应用内共享常量、子工程内共享常量、包内共享常量、类内共享常量
-
常量可穷举,考虑使用枚举
代码格式
- if/for/while/switch/do 等保留字与括号之间都必须加空格
- 任何二目、三目运算符的左右两边都需要加一个空格
- 注释的双斜线与注释内容之间有且仅有一个空格
- 单行字符数限制不超过 120 个,超出需要换行
- 方法参数在定义和传入时,多个参数逗号后边必须加空格。
- 单个方法的总行数不超过 80 行
正例:代码逻辑分清红花和绿叶,个性和共性,绿叶逻辑单独出来成为额外方法,使主干代码更加清晰;共性逻辑抽取成为 共性方法,便于复用和维护。
- 没有必要增加若干空格来使某一行的字符与上一行对应位置的字符对齐。
反例:
public static final float LoginLayoutWidth = 380.4f;
public static final float LoginLayoutHeight = 238.2f;
OOP规约
- 使用intent传值时,避免大数据而导致 TransactionTooLargeException
- 隐式意图之前必须通过 resolveActivity 检查
- 静态方法/变量使用类名访问
- 复写方法增加 @Override
- 禁止过时方法/类的使用
- 包装类型比较使用 equals
- 外部正在调用或者二方库依赖的接口,不允许修改方法签名,避免对接口调用方产生影响。接口过时必须加@Deprecated 注解,并清晰地说明采用的新接口或者新服务是什么。
- Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals
- 当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一起, 便于阅读
- 类内方法定义的顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter 方法
- 慎用 Object 的 clone 方法来拷贝对象
- 类成员与方法访问控制从严
分支控制
- switch 中,每个 case 必须使用 continue/break/return 终止或者注释说明到哪个 case 终止,且必须包含一个default 语句
- switch 传入字符需要判空
- 表达异常的分支时,少用 if-else 方式,这种方式可以改写成:
if (condition) {
...
return obj;
}
// 接着写 else 的业务逻辑代码;
- 超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现。
卫语句示例:
private void login() {
mUserInfo = getUserInfo();
if (mUserInfo == null) {
showLoginView();
return;
}
boolean logout = mUserInfo.isLogout();
boolean loginExpired = mUserInfo.isLoginExpired();
if (logout) {
ViewController.showSwitchAccount();
return;
}
if (!loginExpired) {
loginByToken(mUserInfo);
return;
}
// ...
}
- 不要在条件判断中执行其它复杂的语句,将 复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性
正例:
boolean isValidUsername = username != null && username.length()>6 && (...) && (...)
if(isValidUsername) {
...
}
反例 :
if(username != null && username.length()>6 && (...) && (...)) {
...
}
- 避免采用取反逻辑运算符
正例:使用 if (x < 628) 来表达 x 小于 628。
反例:使用 if (!(x >= 628)) 来表达 x 小于 628。