前言
虽然我们项目的代码时间并不长,也没经过太多人手,但代码的规范性依然堪忧,目前存在较多的比较自由的「代码规范」,这非常不利于项目的维护,代码可读性也不够高,
此外,客户端和后端的研发模式也完全不同,后端研发基本都是基于 SOA 思想的,通常一个子系统 3 个人一起维护就已经是很充分的人力了,更多时候就是 1 个主力 + 1 个 backup 的人力配置。
而客户端却完全不同,大家的代码都是相互交叉的,一个模块的代码可能要经历数十人的蹂躏,所以形成一个一致的开发规范迫在眉睫。
为什么需要一致的代码规范?
核心还是减少沟通成本,提升我们的 Code Review 效率,让我们的代码更加易于维护。此外,一个一致的代码规范可以造成更少的 bug,也就意味着更节省时间和金钱。
当然,规范是约定的,本系列文字全是笔者多年来博采众长,积累而成,所以有任何不同意见,欢迎评论拍砖。
1. Android 的工具规范
工欲善其事,必先利其器。
由于 Android 基本都基于 Android Studio 进行开发,所以工具规范全部以 Android Studio 为前提。
- 必须使用最新的稳定版本的 Android Studio 进行开发;
- 编码格式必须统一为 UTF-8;
-
删除多余的 import,减少警告出现,可利用 AS 的 Optimize Imports(Settings -> Keymap -> Optimize Imports)快捷键,设置自己的喜好。
- 编辑完 .java、.kt、.xml 等文件后必须格式化(需要在设置好以下几点的前提下)
Reformat Code 的必要性,一定需要保证 IDE 配置一致为前提,尽可能贴切于 Android Studio 默认。
强烈建议对于比较长的老代码局部格式化,不全局格式化
-
每行字符数不得超过 160 字符,设置 Editor -> Code Style
-
全部设置为单路径引用,
kotlinx.android.synthetic.main
除外。
以上几处设置完毕,其他采用 Android Studio 默认方式,再进行 Reformat Code 快捷键即可。
2. Android 的分包规范
前面强调了工具的统一配置,再利用 Android Studio 本身的功能便可把代码风格变得一致。接下来就带来第二部分:Android 的分包规范。
对于分包,我们需要达成一致,我们采用 PBF 方式,不推荐使用 PBL 方式。
PBF(按功能分包 Package By Feature)
PBL(按层分包 Package By Layer)
PBF 可能不是很好区分在哪个功能中,不过也比 PBL 要好找很多,且 PBF 与 PBL 相比较有如下优势:
package 内高内聚,package 间低耦合
哪块要添新功能,只改某一个 package 下的东西,而PBL 需要改多个 package,非常麻烦。package 有私有作用域(package-private scope)
原则上一个 package 下的不允许其他类访问都是不应该加上 public 的。很容易删除功能
统计发现新功能没人用,这个版本那块功能得去掉。如果是 PBL,得从功能入口到整个业务流程把受到牵连的所有能删的代码和 class 都揪出来删掉,一不小心就完蛋。如果是 PBF,好说,先删掉对应包,再删掉功能入口(删掉包后入口肯定报错了),完事。高度抽象
解决问题的一般方法是从抽象到具体,PBF 包名是对功能模块的抽象,包内的 class 是实现细节,符合从抽象到具体,而 PBL 弄反了。PBF 从确定 AppName 开始,根据功能模块划分 package,再考虑每块的具体实现细节,而 PBL 从一开始就要考虑要不要 dao 层,要不要 com 层等等。只通过 class 来分离逻辑代码
PBL 既分离 class 又分离 package,而 PBF 只通过 class 来分离逻辑代码。package 的大小有意义了
PBL 中包的大小无限增长是合理的,因为功能越添越多,而 PBF 中包太大(包里 class 太多)表示这块需要重构(划分子包)。
3. Android 的命名规范
代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。正确的英文拼写和语法可以让阅读者易于理解,避免歧义。
注意:即使纯拼音命名方式也要避免采用。但国际通用的名称,可视同英文,比如
toutiao
、douyin
等。
3.1 包名
Android 里面有 package 的概念,所以需要约定一下包名命名规范。
包名全部小写,不允许出现中文、大写字母或者下划线,前面为子模块命名,再根据 PBF 方式进行命名。
3.2 类名
类名都以 UpperCamelCase
风格编写。
类名通常是名词或名词短语,接口名称有时可能是形容词或形容词短语。现在还没有特定的规则或行之有效的约定来命名注解类型。
名词,采用大驼峰命名法,尽量避免缩写,除非该缩写是众所周知的, 比如 HTML、URL,如果类名称中包含单词缩写,则单词缩写的每个字母均应大写。
类 | 描述 | 例如 |
---|---|---|
Activity 类 |
模块名 + Activity |
闪屏页类 SplashActivity |
Fragment 类 |
模块名 + Fragment |
主页类 HomeFragment |
Service 类 |
模块名 + Service |
时间服务 TimeService |
BroadcastReceiver 类 |
功能名 + Receiver |
推送接收 JPushReceiver |
ContentProvider 类 |
功能名 + Provider |
ShareProvider |
自定义 View | 功能名 + View/ViewGroup(组件名称) | ShapeButton |
Dialog对话框 | 功能名+Dialog | ImagePickerDialog |
Adapter 类 |
模块名 + Adapter |
课程详情适配器 LessonDetailAdapter |
解析类 | 功能名 + Parser |
首页解析类 HomePosterParser |
工具方法类 | 功能名 + Utils 或 Manager |
线程池管理类:ThreadPoolManager 日志工具类: LogUtils (Logger 也可)打印工具类: PrinterUtils |
数据库类 | 功能名 + DBHelper |
新闻数据库:NewsDBHelper |
自定义的共享基础类 | Base + 基础 |
BaseActivity , BaseFragment |
抽象类 | Base / Abstract 开头 |
AbstractLogin |
异常类 | Exception 结尾 |
LoginException |
接口 | able / ible 结尾 / I 开头 |
Runnable , Accessible ,ILoginView |
测试类的命名以它要测试的类的名称开始,以 Test 结束。例如:HashTest
或 HashIntegrationTest
。
接口(interface):命名规则与类一样采用大驼峰命名法,多以 able 或 ible 结尾,如 interface Runnable
、interface Accessible
。
注意:如果项目采用 MVP,所有 Model、View、Presenter 的接口都以 I 为前缀,不加后缀,其他的接口采用上述命名规则。
3.3 方法名
方法名都以 lowerCamelCase
风格编写。
方法名通常是动词或动词短语。
方法 | 说明 |
---|---|
initXX() |
初始化相关方法,使用 init 为前缀标识,如初始化布局 initView() |
isXX() , checkXX() |
方法返回值为 boolean 型的请使用 is/check 为前缀标识 |
getXX() |
返回某个值的方法,使用 get 为前缀标识 |
setXX() |
设置某个属性值 |
handleXX() , processXX() |
对数据进行处理的方法 |
displayXX() , showXX() |
弹出提示框和提示信息,使用 display/show 为前缀标识 |
updateXX() |
更新数据 |
saveXX() , insertXX() |
保存或插入数据 |
resetXX() |
重置数据 |
clearXX() |
清除数据 |
removeXX() , deleteXX() |
移除数据或者视图等,如 removeView() |
drawXX() |
绘制数据或效果相关的,使用 draw 前缀标识 |
3.4 变量命名
这里的变量为广义的变量,包括了常量、局部变量、全局变量等,它们的基础规则是:
- 类型需要是名词 / 名词短语;
- 采用
lowerCamelCase
风格;
在具体的变量命名时,会根据该变量的类型不同而附加额外的命名规则:
类型 | 说明 | 例如 |
---|---|---|
常量 | 大写 & 下划线隔开,Kotlin 一定要 const val | const val TYPE_NORMAL = 1 static final TYPE_NORMAL = 1 |
临时变量名 | 整型:i 、j 、k 、m 、n ,字符型一般用 c 、d 、e |
for(int i = 0;i < len; i++) |
其他变量 | lowerCamelCase 风格即可,私有变量也不要使用 m 开头 |
private int tmp; |
Kotlin | 只读变量使用 val ,可变变量使用 var ,尽可能使用 val |
var tmp = 0 val defaultIndex = 0 |
3.5 资源命名
Android 的资源包括:
资源文件命名为全部小写,采用下划线命名法。
3.5.1 动画资源文件(anim/ 和 animator/)
安卓主要包含属性动画和视图动画,其视图动画包括补间动画和逐帧动画。属性动画文件需要放在 res/animator/
目录下,视图动画文件需放在 res/anim/
目录下。命名规则:{模块名_}逻辑名称
。
说明:
{}
中的内容为可选,逻辑名称
可由多个单词加下划线组成。例如:refresh_progress.xml
、market_cart_add.xml
、market_cart_remove.xml
。
如果是普通的补间动画或者属性动画,可采用:动画类型_方向
的命名方式。
例如:
名称 | 说明 |
---|---|
fade_in |
淡入 |
fade_out |
淡出 |
push_down_in |
从下方推入 |
push_down_out |
从下方推出 |
push_left |
推向左方 |
slide_in_from_top |
从头部滑动进入 |
zoom_enter |
变形进入 |
slide_in |
滑动进入 |
shrink_to_middle |
中间缩小 |
3.5.2 颜色资源文件(color/)
color/ 是专门用于存放颜色相关资源的文件夹。命名规则:类型{_模块名}_逻辑名称
。
说明:
{}
中的内容为可选。例如:sel_btn_font.xml
。
颜色资源也可以放于 res/drawable/
目录,引用时则用 @drawable
来引用,但不推荐这么做,最好还是把两者分开。
3.5.3 图片资源文件(drawable/ 和 mipmap/)
res/drawable/
目录下放的是位图文件(.png、.9.png、.jpg、.gif)或编译为可绘制对象资源子类型的 XML 文件,而 res/mipmap/
目录下放的是不同密度的启动图标,所以 res/mipmap/
只用于存放启动图标,其余图片资源文件都应该放到 res/drawable/
目录下。
命名规则:类型{_模块名}_逻辑名称
、类型{_模块名}_颜色
。
说明:
{}
中的内容为可选;类型
可以是可绘制对象资源类型,也可以是控件类型最后可加后缀_small
表示小图,_big
表示大图。
例如:
名称 | 说明 |
---|---|
btn_main_about.png |
主页关于按键 类型_模块名_逻辑名称 |
btn_back.png |
返回按键 类型_逻辑名称 |
divider_maket_white.png |
商城白色分割线 类型_模块名_颜色 |
ic_edit.png |
编辑图标 类型_逻辑名称 |
bg_main.png |
主页背景 类型_逻辑名称 |
btn_red.png |
红色按键 类型_颜色 |
btn_red_big.png |
红色大按键 类型_颜色 |
ic_avatar_small.png |
小头像图标 类型_逻辑名称 |
bg_input.png |
输入框背景 类型_逻辑名称 |
divider_white.png |
白色分割线 类型_颜色 |
bg_main_head.png |
主页头部背景 类型_模块名_逻辑名称 |
def_search_cell.png |
搜索页面默认单元图片 类型_模块名_逻辑名称 |
ic_more_help.png |
更多帮助图标 类型_逻辑名称 |
divider_list_line.png |
列表分割线 类型_逻辑名称 |
sel_search_ok.xml |
搜索界面确认选择器 类型_模块名_逻辑名称 |
shape_music_ring.xml |
音乐界面环形形状 类型_模块名_逻辑名称 |
如果有多种形态,如按钮选择器:sel_btn_xx.xml
,采用如下命名:
名称 | 说明 |
---|---|
sel_btn_xx |
作用在 btn_xx 上的 selector |
btn_xx_normal |
默认状态效果 |
btn_xx_pressed |
state_pressed 点击效果 |
btn_xx_focused |
state_focused 聚焦效果 |
btn_xx_disabled |
state_enabled 不可用效果 |
btn_xx_checked |
state_checked 选中效果 |
btn_xx_selected |
state_selected 选中效果 |
btn_xx_hovered |
state_hovered 悬停效果 |
btn_xx_checkable |
state_checkable 可选效果 |
btn_xx_activated |
state_activated 激活效果 |
btn_xx_window_focused |
state_window_focused 窗口聚焦效果 |
注意:使用 Android Studio 的插件 SelectorChapek 可以快速生成 selector,前提是命名要规范。
3.5.4 布局资源文件(layout/)
命名规则:类型_模块名
、{模块名_}类型_逻辑名称
。(也采用 PBF,方便查看,尤其在大项目中)
说明:
{}
中的内容为可选。
例如:
类型 | 名称 | 说明 |
---|---|---|
Activity |
main_activity.xml |
主窗体 模块名_类型 |
Fragment |
music_fragment.xml |
音乐片段 模块名_类型 |
Dialog |
loading_dialog.xml |
加载对话框 逻辑名称_类型 |
PopupWindow |
info_ppw.xml |
信息弹窗(PopupWindow) 逻辑名称_类型 |
adapter 的列表项 |
main_song_item.xml |
主页歌曲列表项 模块名_类型_逻辑名称 |
3.5.5 布局资源 id 命名
命名规则:{模块名_}_逻辑名_view 缩写(功能)
,例如: main_search_btn
、back_btn
。此外,采用 Kotlinx 直接获取布局文件的时候,id 命名采用驼峰样式。
说明:
{}
中的内容为可选。参考 GoogleSamples Demo:https://github.com/android/architecture-samples
例如:
类型 | 规范 | 命名示例 |
---|---|---|
TextView |
xxx_text |
user_login_text |
EditText |
xxx_edit |
user_login_edit |
ImageView |
xxx_iv |
user_login_iv |
Button |
xxx_btn |
user_login_btn |
CheckBox |
xxx_cb |
user_login_cb |
GridView |
xxx_gv |
user_login_gv |
ListView |
xxx_lv |
user_login_lv |
RecyclerView |
xxx_rv |
user_login_rv |
RadioButton |
xxx_rb |
user_login_rb |
LinearLayout |
xxx_ll |
user_login_ll |
RelativeLayout |
xxx_rl |
user_login_rl |
FrameLayout |
xxx_fl |
user_login_fl |
GridLayout |
xxx_gl |
user_login_gl |
ConstraintLayout |
xxx_cl |
user_login_cl |
3.5.6 菜单资源文件(menu/)
菜单相关的资源文件应放在该目录下。命名规则:{模块名_}逻辑名称
说明:
{}
中的内容为可选。例如:main_drawer.xml
、navigation.xml
。
3.5.7 colors.xml
的 name
命名使用下划线命名法,在你的 colors.xml
文件中应该只是映射颜色的名称一个 ARGB 值,而没有其它的。不要使用它为不同的按钮来定义 ARGB 值。
例如,不要像下面这样做:
#FFFFFF
#2A91BD
#5F5F5F
#939393
#FFFFFF
#FF9D2F
...
#323232
使用这种格式,会非常容易重复定义 ARGB 值,而且如果应用要改变基色的话会非常困难。同时,这些定义是跟一些环境关联起来的,如 button
或者 comment
,应该放到一个按钮风格中,而不是在 colors.xml
文件中。
相反,应该这样做:
#FFFFFF
#DBDBDB
#939393
#5F5F5F
#323232
#27D34D
#2A91BD
#FF9D2F
#FF432F
向应用设计者那里要这个调色板,名称不需要跟 "green"
、"blue"
等等相同。"brand_primary"
、"brand_secondary"
、"brand_negative"
这样的名字也是完全可以接受的。像这样规范的颜色很容易修改或重构,会使应用一共使用了多少种不同的颜色变得非常清晰。通常一个具有审美价值的 UI 来说,减少使用颜色的种类是非常重要的。
注意:如果某些颜色和主题有关,那就单独写一个
colors_theme.xml
。
3.5.8 strings.xml
的 name
命名使用下划线命名法,采用以下规则:{模块名_}逻辑名称
,这样方便同一个界面的所有 string
都放到一起,方便查找。
名称 | 说明 |
---|---|
main_menu_about |
主菜单按键文字 |
friend_title |
好友模块标题栏 |
friend_dialog_del |
好友删除提示 |
login_check_email |
登录验证 |
dialog_title |
弹出框标题 |
button_ok |
确认键 |
loading |
加载文字 |
3.5.9 styles.xml
的
name
命名使用大驼峰命名法,几乎每个项目都需要适当的使用 styles.xml
文件,因为对于一个视图来说,有一个重复的外观是很常见的,将所有的外观细节属性(colors
、padding
、font
)放在 styles.xml
文件中。 在应用中对于大多数文本内容,最起码你应该有一个通用的 styles.xml
文件,例如:
应用到 TextView
中:
或许你需要为按钮控件做同样的事情,不要停止在那里,将一组相关的和重复 android:xxxx
的属性放到一个通用的 中。
4. Android 的注释规范
4.1 类注释
每个类完成后应该有作者姓名和联系方式的注释,对自己的代码负责。
/**
*
* author : nanchen
* e-mail : xxx@xx
* time : 2021/01/18
* desc : xxxx 描述
* version: 1.0
*
*/
public class WelcomeActivity {
...
}
具体可以在 AS 中自己配制,进入 Settings -> Editor -> File and Code Templates -> Includes -> File Header,输入
/**
*
* author : ${USER}
* e-mail : xxx@xx
* time : ${YEAR}/${MONTH}/${DAY}
* desc :
* version: 1.0
*
*/
这样便可在每次新建类的时候自动加上该头注释。
4.2 方法注释
每一个成员方法(包括自定义成员方法、覆盖方法、属性方法)的方法头都必须做方法头注释,在方法前一行输入 /** + 回车
或者设置 Fix doc comment
(Settings -> Keymap -> Fix doc comment)快捷键,AS 便会帮你生成模板,我们只需要补全参数即可,如下所示。@param
, @return
, @throws
, @deprecated
这 4 种标记出现的时候,描述都不能为空。当描述无法在一行中容纳,连续行至少需要再缩进 4 个空格。
/**
* Report an accessibility action to this view's parents for delegated processing.
*
* Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally
* call this method to delegate an accessibility action to a supporting parent. If the parent
* returns true from its
* {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)}
* method this method will return true to signify that the action was consumed.
*
* This method is useful for implementing nested scrolling child views. If
* {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action
* a custom view implementation may invoke this method to allow a parent to consume the
* scroll first. If this method returns true the custom view should skip its own scrolling
* behavior.
*
* @param action Accessibility action to delegate
* @param arguments Optional action arguments
* @return true if the action was consumed by a parent
*/
public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) {
for (ViewParent p = getParent(); p != null; p = p.getParent()) {
if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) {
return true;
}
}
return false;
}
4.3 块注释
块注释与其周围的代码在同一缩进级别。它们可以是 /* ... */
风格,也可以是 // ...
风格(//
后最好带一个空格)。对于多行的 /* ... */
注释,后续行必须从 *
开始, 并且与前一行的 *
对齐。以下示例注释都是 OK 的。
/*
* This is okay.
*/
// And so
// is this.
/* Or you can
* even do this. */
注释不要封闭在由星号或其它字符绘制的框架里。
Tip:在写多行注释时,如果你希望在必要时能重新换行(即注释像段落风格一样),那么使用
/* ... */
。
比如:
4.4 全局变量的注释
全局变量的注释样式如下(注意注释之间有空格):
/**
* The next available accessibility id.
*/
private static int nextAccessibilityViewId;
/**
* The animation currently associated with this view.
*/
protected Animation currentAnimation = null;
4.5 其他一些注释
AS 已帮你集成了一些注释模板,我们只需要直接使用即可,在代码中输入 TODO
、FIXME
等这些注释模板,回车后便会出现如下注释。
// TODO: 17/3/14 需要实现,但目前还未实现的功能的说明
// FIXME: 17/3/14 需要修正,甚至代码是错误的,不能工作,需要修复的说明
4.5 注释必须遵守的规范
4.5.1 不言自明的方法不要加注释。
比如 Item getItem(int index)
是一段自说明的代码,我们可以直接从方法的命名就能知道它是干嘛的,所以不需要增加注释。
4.5.2 提测的代码不应该有 TODO 这样的注释
5. 代码样式规范
5.1 使用标准大括号样式
左大括号不单独占一行,与其前面的代码位于同一行:
class MyClass {
int func() {
if (something) {
// ...
} else if (somethingElse) {
// ...
} else {
// ...
}
}
}
我们需要在条件语句周围添加大括号。例外情况:如果整个条件语句(条件和主体)适合放在同一行,那么您可以(但不是必须)将其全部放在一行上。例如,我们接受以下样式:
if (condition) {
body();
}
同样也接受以下样式:
if (condition) body();
但不接受以下样式:
if (condition)
body(); // bad!
5.2 编写简短方法
在可行的情况下,尽量编写短小精炼的方法。我们了解,有些情况下较长的方法是恰当的,因此对方法的代码长度没有做出硬性限制。如果某个方法的代码超出 40 行,请考虑是否可以在不破坏程序结构的前提下对其拆解。
5.3 类成员的顺序
这并没有唯一的正确解决方案,但如果都使用一致的顺序将会提高代码的可读性,推荐使用如下排序:
- 常量(Kotlin 伴生对象放在开头)
- 字段
- 构造函数
- 重写函数和回调
- 公有函数
- 私有函数
- 内部类或接口
例如:
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
private String mTitle;
private TextView mTextViewTitle;
@Override
public void onCreate() {
...
}
public void setTitle(String title) {
mTitle = title;
}
private void setUpView() {
...
}
static class AnInnerClass {
}
}
如果类继承于 Android 组件(例如 Activity
或 Fragment
),那么把重写函数按照他们的生命周期进行排序是一个非常好的习惯,例如,Activity
实现了 onCreate()
、onDestroy()
、onPause()
、onResume()
,它的正确排序如下所示:
public class MainActivity extends Activity {
//Order matches Activity lifecycle
@Override
public void onCreate() {}
@Override
public void onResume() {}
@Override
public void onPause() {}
@Override
public void onDestroy() {}
}
5.4 函数参数的排序
在 Android 开发过程中,Context
在函数参数中是再常见不过的了,我们最好把 Context
作为其第一个参数。
正相反,我们把回调接口应该作为其最后一个参数。
例如:
// Context always goes first
public User loadUser(Context context, int userId);
// Callbacks always go last
public void loadUserAsync(Context context, int userId, UserCallback callback);
5.5 字符串常量的命名和值
Android SDK 中的很多类都用到了键值对函数,比如 SharedPreferences
、Bundle
、Intent
,所以,即便是一个小应用,我们最终也不得不编写大量的字符串常量。
当时用到这些类的时候,我们 必须 将它们的键定义为 static final
字段,并遵循以下指示作为前缀。
类 | 字段名前缀 |
---|---|
SharedPreferences | PREF_ |
Bundle | BUNDLE_ |
Fragment Arguments | ARGUMENT_ |
Intent Extra | EXTRA_ |
Intent Action | ACTION_ |
说明:虽然 Fragment.getArguments()
得到的也是 Bundle
,但因为这是 Bundle
的常用用法,所以特意为此定义一个不同的前缀。
例如:
// 注意:字段的值与名称相同以避免重复问题
static final String PREF_EMAIL = "PREF_EMAIL";
static final String BUNDLE_AGE = "BUNDLE_AGE";
static final String ARGUMENT_USER_ID = "ARGUMENT_USER_ID";
// 与意图相关的项使用完整的包名作为值的前缀
static final String EXTRA_SURNAME = "com.myapp.extras.EXTRA_SURNAME";
static final String ACTION_OPEN_USER = "com.myapp.action.ACTION_OPEN_USER";
5.6 行长限制
代码中每一行文本的长度都应该不超过 160 个字符。虽然关于此规则存在很多争论,但最终决定仍是以 160 个字符为上限,如果行长超过了 160(AS 窗口右侧的竖线就是设置的行宽末尾 ),我们通常有两种方法来缩减行长。
- 提取一个局部变量或方法(最好)。
- 使用换行符将一行换成多行。
不过存在以下例外情况:
- 如果备注行包含长度超过 160 个字符的示例命令或文字网址,那么为了便于剪切和粘贴,该行可以超过 160 个字符。
- 导入语句行可以超出此限制,因为用户很少会看到它们(这也简化了工具编写流程)。
5.6.1 换行策略
这没有一个准确的解决方案来决定如何换行,通常不同的解决方案都是有效的,但是有一些规则可以应用于常见的情况。
5.6.1.1 操作符的换行
除赋值操作符之外,我们把换行符放在操作符之前,例如:
int longName = anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne
+ theFinalOne;
赋值操作符的换行我们放在其后,例如:
int longName =
anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne + theFinalOne;
5.6.1.2 函数链的换行
当同一行中调用多个函数时(比如使用构建器时),对每个函数的调用应该在新的一行中,我们把换行符插入在 .
之前。
例如:
Picasso.with(context).load("https://blankj.com/images/avatar.jpg").into(ivAvatar);
我们应该使用如下规则:
Picasso.with(context)
.load("https://blankj.com/images/avatar.jpg")
.into(ivAvatar);
5.6.1.3 多参数的换行
当一个方法有很多参数或者参数很长的时候,我们应该在每个 ,
后面进行换行。
比如:
loadPicture(context, "https://blankj.com/images/avatar.jpg", ivAvatar, "Avatar of the user", clickListener);
我们应该使用如下规则:
loadPicture(context,
"https://blankj.com/images/avatar.jpg",
ivAvatar,
"Avatar of the user",
clickListener);
5.6.1.4 RxJava 链式的换行
RxJava 的每个操作符都需要换新行,并且把换行符插入在 .
之前。
例如:
public Observable syncLocations() {
return mDatabaseHelper.getAllLocations()
.concatMap(new Func1>() {
@Override
public Observable extends Location> call(Location location) {
return mRetrofitService.getLocation(location.id);
}
})
.retry(new Func2() {
@Override
public Boolean call(Integer numRetries, Throwable throwable) {
return throwable instanceof RetrofitError;
}
});
}
参考文档:
https://source.android.com/source/code-style?hl=zh-cn
https://developer.android.com/kotlin/style-guide?hl=zh-cn
https://github.com/Blankj/AndroidStandardDevelop