Android代码规范指北

统一的代码风格在多人协作开发中的作用是不言而喻的,通过参考一些比较优秀的实践,这里大量参考了阿里巴巴 JAVA 开发手册 ,再结合了个人的思考,制定了这么一套规范,由于个人的认识是非常有限的,本规范也肯定存在很多不合理和需要补充的东西,在这里恳请大家根据自己的实践和工作中,提出一些中肯的建议和修改意见。

意义

  1. 高度有秩序的代码具有天然的美感,写代码的人心情会好很多。
  2. 减低开发人员流动带来的风险。
  3. 对于新人能更好地理解和参与到开发中。
  4. 更好的可维护性。
  5. 随之带来更好的产品质量和开发效率提升。

命名规约

  • 【强制】所有编程相关命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。
  • 【强制】所有编程相关的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。
  • 【强制】方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式。

类的命名

  • 【强制】抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类命名以它要测试的类的名称开始,以 Test 结尾。
  • 【强制】相关组件类应该以组件名作为后缀以便识别。
组件命名规则命名举例
Activity×××ActivityMainActivity
Fragment×××FragmentHomeFragment
Dialog×××DialogAlertDialog
Service×××ServiceDownloadService
BroadcastReceiver×××ReceiverLoginReceiver
ContentProvider×××ProviderUserProvider
Adapter名字+类型+AdapterArticleListAdapter, ImageGridAdapter
AsyncTask×××TaskLoginTask
Handler名字+所在线程+HandlerHomeUIHandler, CompressWorkHandler
ViewHolderVH + 名字VHArticle
  • 【推荐】实用工具类命名成 **Utils**Helper
  • 【推荐】EventBus 发布的事件名命名成以 Event 结尾,比如 LoginEvent
  • 【推荐】如果使用到了设计模式,建议在类名中体现出具体模式。
  • 【推荐】接口一般以大写 I 开头,回调的接口一般为 Listener 或者 Callback 结尾。

方法命名

  • 【强制】POJO 类中的任何布尔类型的变量,都不要加 is,否则部分框架解析会引起序列化错误。 ==反例==:定义为基本数据类型 boolean isSuccess; 的属性,它的方法也是 isSuccess() ,部分Json 框架在反向解析的时候,“以为”对应的属性名称是 success,导致属性获取不到,进而抛出异常。
  • 【强制】EventBus 回调的方法必须和相关 Event 类一致,比如LoginEvent类的方法签名为: public final void onLoginEvent(LoginEvent e);
  • 【推荐】客户端逻辑大部分是基于事件驱动的,应该以on来开头,比如登录按钮的点击可以是:onLoginClick()

变量命名

  • 【强制】常量命名全部大写,单词间用下划线隔开。
  • 【强制】局部变量和一般类变量以小写字母开头。
  • 【推荐】static 类变量名称以s开头,final类变量用f开头。
  • 【推荐】组件相关的可以用【全部首字母+名字】的命名,比如 id 是 R.id.tv_login 的控件名称是:tvLogin

资源文件命名

除了 attr 和 style 资源遵循驼峰命名之外,其他资源的命名统一用小写字母+下划线的风格。

  • 【推荐】布局文件命名
布局类型命名规则例子
Activityactivity_×××HomeActivity 对应 activity_home
Dialogdlg_×××LoginDialog 对应 dlg_login
Fragmentfrag_×××HomeFragment 对应 frag_home
页面标题title_×××title_main
列表Footerfooter_×××footer_article
列表Headerheader_×××header_article
列表的Itemitem_×××item_article
可重用嵌入布局include_ ×××include_navagator
分割线line_+颜色+大小line_gray_1px
  • 【推荐】id命名:截取相关组件首个字母作为开头,然后以下划线作为分割。比如【TextView:tv_name】。
  • 【推荐】图片命名:【类别+名称+状态(如果有)】,根据图片的用途可以分类为图标「ic」,背景「bg」,前景「fg」(比较少用到),图片「img」(比如引导图,开机页面),如果有多个状态用同一张图,那么首选声明为 【××_selected】 。
状态示例
正常状态ic_login_primary
checkedic_login_checked
pressedic_login_pressed
selectedic_login_selected
disableic_login_disable
  • 【推荐】drawable命名
  1. xml定义图形:参考图片命名规则,在以上基础上添加辨识,比如: bg_login_shape, bg_login_vector, bg_login_shape_primary。
  2. 多个状态drawable: 命名为 【××_selector】,比如 bg_login_selector。
  • 【推荐】颜色命名
  1. 单色:命名规则为【类型+名字+状态(如果有)】,我把用到颜色的元素类型做了个归类,分别是字体「text」,背景「bg」,线「line」,还是一些常规色(比如白色,透明等),正例:text_black_primary, bg_black_selected, line_orange。
  2. 字体selector颜色:【名字 + text_selector】 ,比如 tab_item_text_selector。
  • 【推荐】尺寸命名:通用性比较强和需要适配的在 dimens.xml 中设置,一般的可以在代码中直接写。
  1. 字体大小: 【font_××】,××和设计稿保持一致的换算。
  2. 间距:组件外用【××_margin】,组件内用【××_padding】, 例子: app_left_margin。
  3. 控件大小:【宽度:××_width】,【高度:××_height】,其他【××_size】,例子: login_button_height。
  • 【推荐】其他:文字不得直接写到 java 代码和 layout 代码里面,应该抽离到相关的 strings 资源文件中;menu 和动画资源命名不需要加前缀或者后缀,能表达意图即可,因为 R.menu 或者 R.anim 已经携带了相关的信息。

代码风格

  • 【强制】大括号的使用约定。如果是大括号内为空,则简洁地写成{}即可,不需要换行;如果 是非空代码块则:
  1. 左大括号前不换行。
  2. 左大括号后换行。
  3. 右大括号前换行。
  4. 右大括号后还有 else 等代码则不换行;表示终止右大括号后必须换行。
  • 【强制】 左括号和后一个字符之间不出现空格;同样,右括号和前一个字符之间也不出现空格; 代码块缩进 4 个空格,如果使用 tab 缩进,请设置成 1 个 tab 为 4 个空格。
正例:
public static void main(String args[]) {
    // 缩进 4 个空格
    String say = "hello";
    // 运算符的左右必须有一个空格
    int flag = 0;
    // 关键词 if 与括号之间必须有一个空格,括号内 f 与左括号,1 与右括号不需要空格
    if (flag == 0) {
        System.out.println(say);
    }
    
    // 左大括号前加空格且不换行;左大括号后换行
    if (flag == 1) {
        System.out.println("world");
    // 右大括号前换行,右大括号后有 else,不用换行
    } else {
        System.out.println("ok");
    // 右大括号做为结束,必须换行
    }
} 

  • 【强制】任何运算符左右必须加一个空格。

说明:运算符包括赋值运算符 =、逻辑运算符 &&、加减乘除符号、三目运行符等。

  • 【强制】方法参数在定义和传入时,多个参数逗号后边必须加空格。
  • 【强制】单行字符数限制不超过 120 个,超出需要换行,换行时,遵循如下原则:
  1. 换行时相对上一行缩进 4 个空格。
  2. 运算符与下文一起换行。
  3. 方法调用的点符号与下文一起换行。
  4. 在多个参数超长,逗号后进行换行。
  5. 在括号前不要换行,见反例。
正例:
StringBuffer sb = new StringBuffer();
//超过 120 个字符的情况下,换行缩进 4 个空格,并且方法前的点符号一起换行
sb.append("zi").append("xin")…
    .append("huang");

反例:
StringBuffer sb = new StringBuffer();
//超过 120 个字符的情况下,不要在括号前换行
sb.append("zi").append("xin")…append
    ("huang");
//参数很多的方法调用也超过 120 个字符,逗号后才是换行处
method(args1, args2, args3, ...
    , argsX); 
  • 【强制】方法参数在定义和传入时,多个参数逗号后边必须加空格。

正例:下例中实参的 "a" ,后边必须要有一个空格。method("a", "b", "c");

  • 【强制】在 if/else/for/while/do 语句中必须使用大括号,即使只有一行代码,避免使用下面的形式:if (condition) statements;

  • 【推荐】推荐尽量少用 else, if-else 的方式可以改写成:

if(condition){
     …
    return obj;
} 
说明:如果使用要 `if-else if-else` 方式表达逻辑,【强制】请勿超过 3 层,超过请使用状态设计模式。
  • 【推荐】循环体中的语句要考量性能,以下操作尽量移至循环体外处理,如定义对象、变量,进行不必要的 try-catch 操作(这个 try-catch 是否可以移至循环体外),遍历长度的提前获取;避免使用 foreach,迭代器,尽量采用下标的形式
正例:
(for i=0 ;i <size; ++i)

反例:
for(int i : items)

编码规约

OOP 规约

  • 【强制】过时的类或者方法不要使用,覆盖的方法要用Override声明。这样当写错覆盖方法时可以得到编译错误提示。
  • 【强制】Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。
  • 【强制】单例或者实用类构造方法应该声明为 private。
  • 【强制】如果用到 FastJson 来解析数据,必须在相关 getter 和 setter 方法上添加注解。
  • 【推荐】声明为 public 的方法要对参数进行校验,private 的可以不用。
  • 【推荐】当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一起,便于阅读。
  • 【推荐】 类内方法定义顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter 方法。
  • 【推荐】循环体内,字符串的联接方式,使用 StringBuilder 的 append 方法进行扩展。
  • 【推荐】类成员与方法访问控制从严:
  1. 如果不允许外部直接通过 new 来创建对象,那么构造方法必须是 private。
  2. 工具类不允许有 public 或 default 构造方法。
  3. 类非 static 成员变量并且与子类共享,必须是 protected。
  4. 类非 static 成员变量并且仅在本类使用,必须是 private。
  5. 类 static 成员变量如果仅在本类使用,必须是 private。
  6. 若是 static 成员变量,必须考虑是否为 final。
  7. 类成员方法只供类内部调用,必须是 private。
  8. 类成员方法只对继承类公开,那么限制为 protected。

常量定义

  • 【强制】不允许出现任何魔法值(即未经定义的常量)直接出现在代码中。
  • 【强制】long 或者 Long 初始赋值时,必须使用大写的 L,不能是小写的 l ,小写容易跟数字 1 混淆,造成误解。
  • 【推荐】不要使用一个常量类维护所有常量,应该按常量功能进行归类,分开维护。如:缓存 相关的常量放在类:CacheConsts 下;系统配置相关的常量放在类:ConfigConsts 下。
  • 【推荐】避免使用枚举类型,用@IntDef进行替代。

异常处理

  • 【强制】捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容。
反例:
void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) { }
}
  • 【强制】异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低。
  • 【强制】finally 块必须对资源对象、流对象进行关闭,有异常也要做 try-catch。
  • 【强制】不能在 finally 块中使用 return,finally 块中的 return 返回后方法结束执行,不会再执行 try 块中的 return 语句。
  • 【强制】捕获异常与抛异常,必须是完全匹配,或者捕获异常是抛异常的父类。==说明==:如果预期抛的是绣球,实际接到的是铅球,就会产生意外情况。
  • 【推荐】不要偷懒直接捕获顶级异常,这样会把Runtime的异常也囊括进来,要明确每种异常出现的场景被给出相应的处理。
反例:
try {
    someComplicatedIOFunction();        // may throw IOException
    someComplicatedParsingFunction();   // may throw ParsingException
    someComplicatedSecurityFunction();  // may throw SecurityException
    // phew, made it all the way
} catch (Exception e) {                 // I'll just catch all exceptions
    handleError();                      // with one generic handler!
}
  • 【推荐】除非有充分的理由,不要捕获 Java 类库中定义的继承自 RuntimeException 的运行时异常类,如:IndexOutOfBoundsException / NullPointerException,这类异常由程序员预检查来规避,保证程序健壮性。

代码注释

  • 【强制】类、类属性、类方法的注释必须使用 javadoc 规范,使用/*内容/格式,不得使用//xxx 方式。
  • 【强制】所有的抽象方法(包括接口中的方法)必须要用 javadoc 注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。
  • 【强制】所有的类都必须添加创建者信息。
  • 【强制】对那些临时性的、短期的、够棒但不完美的代码,请使用TODO注释。
// TODO: Change this to use a flag instead of a constant.
  • 【强制】方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用/* */注释,注意与代码对齐。
void method(){
    // 打个招呼
    sayHello();
    
    /*
      这里保持移动,
      并不断对步数加1
     */
    keepMove();
}
  • 【参考】好的命名、代码结构是自解释的,注释力求精简准确、表达到位。避免出现注释的一 个极端:过多过滥的注释,代码的逻辑一旦修改,修改注释是相当大的负担。

Android 实践

  • 【强制】避免对同个 View 进行多次查找,应该缓存起来,比如列表中使用的 ViewHolder 模式。
反例:
view.findViewById(R.id.iv_toolbar_right).setOnClickListener(this);
view.findViewById(R.id.iv_toolbar_right).setEnabled(true);
  • 【强制】不要使用 System.out.println() ,printf() 打印日志。
  • 【强制】调试日志要有个开关,在正式发布的时候不能出现应用日志打印。
  • 【强制】读文件,数据库,网络请求等一些耗时操作必须在异步线程中执行。
  • 【强制】不能粗暴的把 Activity, Service 对象或者一些比较重的对象直接声明为 static 变量,如果必须这么做,请注意它们的生命周期变化。
  • 【强制】每引入一个第三方库,要检查是否加入相关的混淆规则。
  • 【强制】自定义属性动画 (ObjectAnimator) 的 getter 和 setter 方法时要注意防止混淆。
  • 【强制】在 (Activity,Fragment) 组件退出时要保证相关资源得到释放,比如 EventBus 订阅的事件,注册的广播,轮播任务等。
  • 【强制】对于Api Level大于等于23的设备要进行运行时权限检查。
  • 【推荐】在使用 Thread,Handler,AsyncTask,Timer,耗时的匿名回调类,内部类时,考虑声明成静态的内部类,并且弱引用或者软引用来处理相关的大对象,并且要注意生命周期的变化,避免出现内存泄漏问题。
  • 【推荐】利用 TextView 的drawableLeft等来减少 ImageView 的使用。
  • 【推荐】通过使用 RelativeLayout 或者 ConstraintLayout 来减少布局的层次。
  • 【推荐】在 findViewById 尽可能选取一个比较近的父节点来减少查找时间。
  • 【推荐】Bundle 中的常量 Key 值统一在一个文件中,而不是直接在 Activity 或者 Fragment 中,比如 BundleKeys 文件中。
  • 【推荐】可滑动列表复用的 ViewHolder 对象中,对于一些事件对象应该尽可能地复用。
  • 【推荐】对隐式 Intent 的运行时调用 resolveActivity 进行检查保护。
  • 【推荐】使用 NotificationCompat 兼容包来处理消息通知。
  • 【推荐】延迟创建没有用到的对象,比如 Adapter 的列表对象,应该在请求数据取到之后再去创建,而不是提前创建好。
  • 【推荐】使用 ArrayMap,Sparse×× 系列对象来减少内存消耗和避免AutoBoxing。
  • 【推荐】更新列表局部数据避免粗暴地调用 Adapter.notifyDataSetChanged,应该只更新变化的部分。
  • 【推荐】用 @Nullable, @NonNull, @IdRes, @MainThread 等Support Annotations注解来增强代码的编译期检查和可读性。
  • 【参考】如果不用getColor(int id, Theme theme)等相关方法,至少使用 ContextCompat 来获取相关 Color 或者图片资源。
  • 【参考】尽可能通过 Fragment 来实现视图层,Activity 只是负责嵌入和管理。
  • 【参考】通过 Picasso,Glide 等开源组件去加载和缓存你的图片。

资料参考

  1. 阿里巴巴 JAVA 开发手册
  2. Android Code Style Rules
  3. 常见的八种导致 APP 内存泄漏的问题
  4. Android开发最佳实践
  5. Android Support Annotations

github博客原文:Android代码规范指北

转载于:https://my.oschina.net/daxia/blog/865786

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本书是一本Android进阶类书籍,采用理论、源码和实践相结合的方式来阐述高水准的Android应用开发要点。本书从三个方面来组织内容。第一,介绍Android开发者不容易掌握的一些知识点;第二,结合Android代码和应用层开发过程,融会贯通,介绍一些比较深入的知识点;第三,介绍一些核心技术和Android的性能优化思想。 第1章 Activity的生命周期和启动模式 1 1.1 Activity的生命周期全面分析 1 1.1.1 典型情况下的生命周期分析 2 1.1.2 异常情况下的生命周期分析 8 1.2 Activity的启动模式 16 1.2.1 Activity的LaunchMode 16 1.2.2 Activity的Flags 27 1.3 IntentFilter的匹配规则 28 第2章 IPC机制 35 2.1 Android IPC简介 35 2.2 Android中的多进程模式 36 2.2.1 开启多进程模式 36 2.2.2 多进程模式的运行机制 39 2.3 IPC基础概念介绍 42 2.3.1 Serializable接口 42 2.3.2 Parcelable接口 45 2.3.3 Binder 47 2.4 Android中的IPC方式 61 2.4.1 使用Bundle 61 2.4.2 使用文件共享 62 2.4.3 使用Messenger 65 2.4.4 使用AIDL 71 2.4.5 使用ContentProvider 91 2.4.6 使用Socket 103 2.5 Binder连接池 112 2.6 选用合适的IPC方式 121 第3章 View的事件体系 122 3.1 View基础知识 122 3.1.1 什么是View 123 3.1.2 View的位置参数 123 3.1.3 MotionEvent和TouchSlop 125 3.1.4 VelocityTracker、GestureDetector和Scroller 126 3.2 View的滑动 129 3.2.1 使用scrollTo/scrollBy 129 3.2.2 使用动画 131 3.2.3 改变布局参数 133 3.2.4 各种滑动方式的对比 133 3.3 弹性滑动 135 3.3.1 使用Scroller 136 3.3.2 通过动画 138 3.3.3 使用延时策略 139 3.4 View的事件分发机制 140 3.4.1 点击事件的传递规则 140 3.4.2 事件分发的源码解析 144 3.5 View的滑动冲突 154 3.5.1 常见的滑动冲突场景 155 3.5.2 滑动冲突的处理规则 156 3.5.3 滑动冲突的解决方式 157 第4章 View的工作原理 174 4.1 初识ViewRoot和DecorView 174 4.2 理解MeasureSpec 177 4.2.1 MeasureSpec 177 4.2.2 MeasureSpec和LayoutParams的对应关系 178 4.3 View的工作流程 183 4.3.1 measure过程 183 4.3.2 layout过程 193 4.3.3 draw过程 197 4.4 自定义View 199 4.4.1 自定义View的分类 200 4.4.2 自定义View须知 201 4.4.3 自定义View示例 202 4.4.4 自定义View的思想 217 第5章 理解RemoteViews 218 5.1 RemoteViews的应用 218 5.1.1 RemoteViews在通知栏上的应用 219 5.1.2 RemoteViews在桌面小部件上的应用 221 5.1.3 PendingIntent概述 228 5.2 RemoteViews的内部机制 230 5.3 RemoteViews的意义 239 第6章 Android的Drawable 243 6.1 Drawable简介 243 6.2 Drawable的分类 244 6.2.1 BitmapDrawable 244 6.2.2 ShapeDrawable 247 6.2.3 LayerDrawable 251 6.2.4 StateListDrawable 253 6.2.5 LevelListDrawable 255 6.2.6 TransitionDrawable 256 6.2.7 Ins
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值