Skip to content

getActivity/AndroidCodeStandard

Repository files navigation

Android 代码规范文档

  • 项目地址:Github

  • 鸿洋力荐:荐一份 Android 代码规范建议文档

  • 做开源几年了,被很多人夸过,你的代码写得比较规范,甚至有人质疑自己代码的写法,但是迟迟没有出一个代码规范,说来惭愧,只是因为我早几年写的代码还不够规范,不敢出来误导大家,而代码规范是后续才慢慢养成的,在这个过程中,我不仅参考了大公司出的代码规范文档,也研究了很多关于谷歌源码的编码规范,同时我也在无时不刻在思考,如何能写出让别人更好理解的代码,自打入行以来,我就在一直在这个问题上面探索。

  • 为什么要做成一个开源项目?因为项目会长期更新,大家如果对里面一些规范表示不能理解的或者感觉写得不太对的,又或者有什么想要补充的,随时欢迎你通过 issue 反馈给我,大家的建议很重要,是我做好这件事的关键,我会认真对待和思考提出的每一个建议。同时我也相信一份好的代码规范经得住大众的反复推敲和不断实践,在这里也欢迎你提出自己的想法和建议。

  • 这份代码规范文档开始编写的时间是 2020 年 7 月,中间不断地修改和补充,于 2021 年 1 月发布定稿,同年 2 月,纠正和补充了一些代码规范,从 0 到 1,从不成熟到成熟,整个过程耗时 200 多天。原因是我积累了很多开发的好习惯,但是一直没有任何记录,在短时间将这些东西全部输出几乎不可能,所以我前面花了很多时间回忆和总结,这段时间内我做的最多的一件事是,代码写着写着就去写代码规范文档,直到后面发布初稿时,我又投入了大把的时间和精力来做这件事。大家心中可能都有一个疑问,我为什么不用网上写的,直接照抄照搬,又或者直接采用阿里的,这样不是简单轻松多了?关于这个问题,可以跟大家谈谈我的想法,我看过很多关于 Android 代码规范文档,但是我感觉存在一些问题,可以跟大家分享一下:

    1. 说服力低:是很多代码规范文档只告诉你应该这样写,但是基本没有人提及这样写的好处,那样写不好的地方。他们只会告诉你规则,但是从不告诉你前因后果,这样写出来的代码规范难以服众。

    2. 不够全面:例如后台接口规范、接口实现规范、异常捕获规范、第三方框架使用规范、代码硬编码规范、资源硬编码规范、多模块规范;这些是我们开发中所避不开的东西,但是现在网上的代码规范文档却很少有人提及。

    3. 不够细致:我举个最简单的例子,很多代码规范文档都会说 String ID模块 + 作用 来命名,但是没有人提及过在其他情况下的处理,例如:确定取消 这种字符串,虽然在很多模块中使用到了,但是它却不属于任何模块的,这个时候该怎么命名?这个虽然是小细节,但足以看出文档在细节处理上不够完美和严谨。

更新日志

目录

前言

  • 代码规范是我们每个程序员要做的事,假设我们按照自己的喜好来写代码,那么很可能出现的问题就是我看不懂你的代码或者你看不懂我的代码,这样会给后续维护形成巨大的障碍。这个时候问题来了,如何让代码不分你我,或许只需要一套规则,你和我都认可并且遵守的代码规范守则。

  • 那么你的疑问可能又来了,怎么样才能算好的代码规范,答案只有一个,真正好的代码规范就是别人的代码你一眼就能看懂,更不需要反复去看。之所以这样并不是因为看的人 Review 代码的能力有多强,而是写代码的人愿意遵守规则,他知道自己想这么写,但是知道你会看不懂,所以换了一种方式来写,这种方式就是代码规范

  • 代码规范:一个好的代码规范可以帮助我们快速了解和熟悉相关的业务,降低后续维护的成本(二次开发或者排查问题)。

  • 代码不规范:代码不规范会导致项目可读性变差,具体表现为难分辨和难理解,在无形之中加大项目后续维护的成本。

  • 经验总结:编码不规范,同行泪两行

代码规范原则

  • 在讲之前,我们先思考一个问题,代码规范的出现是为了什么?不就为了让我们更好地进行团队协作和项目维护吗?没错的,所以代码规范原则应该围绕这两个目标进行。

    • 特事特办:代码规范文档只能解决 99% 场景下的问题,特殊情况应该要特殊处理,违背者需要给出合理的解释,建议在代码中直接用注释注明,这样可以减少沟通成本,否则在一般情况下应当要遵守代码规范文档上的约束。

    • 以人为本:我们应该衡量不同写法带来的优点和缺点,然后根据当前项目的实际需求做出合适的选择或者变化。规则是人定的,不是一成不变的。在制定新的规则或者修改旧的规则之前应当先参考和分析谷歌或者知名公司的做法,然后与团队中的各个成员沟通和协商好

    • 实事求事:任何代码规范都应该追求在实际开发中发挥的作用或者效果,规则始终是规则,不能单纯为了制定规则而编写代码规范,而是更应该追求写法的实用性,实用性应该从代码理解的难易程度代码可维护性代码可复用性代码可扩展性等方面因素综合考虑,其次是考虑代码的视觉美观性

常规规范

  • 使用 0px 代替 0dp,这样就可以在获取时避免系统进行换算,提升代码的执行效率。

  • 字符串比较,应该用 "xxx".equals(object),而不应该用 object.equals("xxx"),因为 object 对象可能为空,我们应该把不为空的条件放置在表达式的前面。

  • 字符串类型转换,应该用 String.valueOf(Object object) 来代替 object.toString(),因为 object 对象可能会为空, 直接调用 toString 方法可能会触发 NullPointerException,而 valueOf 方法内部有做判空处理。

  • long 类型的常量应该以大写英文 L 结尾,而不应该用小写英文 l,因为小写英文的 l 会和数字 1 容易造成一些混淆,例如 1l 会被看成 11,而使用 1L 就不会出现这种情况。

  • 尽量采用 switch case 来判断,如果不能实现则再考虑用 if else,因为在多条件下使用 switch case 语句判断会更加简洁。

  • 严禁用 switch case 语句来判断资源 id,因为 Gradle 在 5.0 之后的版本,资源 ID 将不会以常量的形式存在,而 switch case 语句只能判断常量,所以不能再继续使用 switch case 来判断资源 ID 了。

  • 不推荐用 layout_marginLeft,而应该用 layout_marginStart;不推荐用 layout_marginRight,而应该用 layout_marginEnd,原因有两个,一个是适配 Android 4.4 反方向特性(可在开发者选项中开启),第二个是 XML 布局中使用 layout_marginLeftlayout_marginRight 会有代码警告,padding 属性也是同理,这里不再赘述。另外有一点需要注意:严禁 Left、Right 属性和 Start、End 属性同时使用,两者只能二选一。

  • 如果在 layout_marginStartlayout_marginEnd 的值相同的情况下,请替换使用 layout_marginHorizontal,而 layout_marginToplayout_marginBottom 也同理,请替换使用 layout_marginVertical,能用一句代码能做的事不要写两句,padding 属性也是同理,这里不再赘述。

  • 过期高版本 的 API 一定要做对应的兼容(包含 Java 代码和 XML 属性),如果不需要兼容处理的,需要对警告进行抑制。

  • 在能满足需求的情况下,尽量用 invisible 来代替 gone,因为 gone 会触发当前整个 View 树进行重新测量和绘制。

  • apiimplementation,在能满足使用的情况下,优先选用 implementation,因为这样可以减少一些编译时间

  • ListViewRecyclerView 都能实现需求的前提下,优先选用 RecyclerView,具体原因不解释,大家应该都懂。

  • ScrollViewNestedScrollView 都能实现需求的前提下,优先选用 NestedScrollView,是因为 NestedScrollViewRecyclerView 支持相互嵌套,而 ScrollView 是不支持嵌套滚动的。

  • 不能在项目中创建副本文件,例如创建 HomeActivity2.javahome_activity_v2.xml 类似的副本文件,因为这样不仅会增加项目的维护难度,同时对编译速度也会造成一定的影响,正确的做法应该是在原有的文件基础上面修改,如果出现需求变更的情况,请直接使用 Git 或者 SVN 进行版本回退。

  • 如果一个类不需要被继承,请直接用 final 进行修饰,如果一个字段在类初始化过程中已经赋值并且没有地方进行二次赋值,也应当用 final 修饰,如果一个字段不需要被外部访问,那么需要用 private 进行修饰。

  • 时间间隔的计算,对于前后时间的获取,不推荐使用 System.currentTimeMillis() 来获取,因为用户随时可能会调整手机的日期,这样会导致计算出来的时间间隔不准确,推荐使用 SystemClock.uptimeMillis() 来获取,此 API 用于获取本次已开机的毫秒数,用户就算调整了手机的日期也没有任何影响;值得一提的是,Handler 类中的 postDelayed 方法也是采用这种方式实现。

  • 每个小组成员应当安装阿里巴巴代码约束插件,并及时地对插件所提示的代码警告进行处理或者抑制警告。

  • 应用图标应该放在 mipmap 目录下,其他图片资源应当放到 drawable 目录下,具体原因可以看谷歌官方文档对这两个文件夹给出的介绍:

目录 资源类型
drawable 位图文件(.png.9.png.jpg.gif)或编译为以下可绘制对象资源子类型的 XML 文件:位图文件九宫格(可调整大小的位图)状态列表形状动画可绘制对象其他可绘制对象请参阅 Drawable 资源
mipmap 适用于不同启动器图标密度的可绘制对象文件。如需了解有关使用 mipmap 文件夹管理启动器图标的详细信息,请参阅管理项目概览

后台接口规范

  • 后台返回的 id 值,不要使用 int 或者 long 类型来接收,而应该用 string 类型来接收,因为我们不需要对这个 id 值进行运算,所以我们不需要关心它是什么类型的。

  • 后台返回的金额数值应该使用 String 来接收,而不能用浮点数来接收,因为 float 或者 double 在数值比较大的情况下会容易丢失精度,并且还需要自己手动转换出想要保留的小数位,最好的方式是后台返回什么前端就展示什么,而到了运算的时候,则应该用 BigDecimal 类来进行转换和计算,当然金额在前端一般展示居多,运算的情况还算是比较少的。

  • 我们在定义后台返回的 Bean 类时,不应当将一些我们没有使用到的字段添加到代码中,因为这样会消耗性能,因为 Gson 是通过反射将后台字段赋值到 Java 字段中,所以我们应当避免一些不必要的字段解析,另外臃余的字段也会给我们排查问题造成一定的阻碍。

  • 如果后台给定的字段名不符合代码命名的时候,例如当遇到 student_name 这种命名时,我们应当使用 Gson 框架中的 @SerializedName 注解对字段进行映射。

  • 请求的接口参数和返回字段必须要写上注释,除此之外还应该备注对应的后台接口文档地址,以便我们后续能够更好地进行维护和迭代。

  • 后台返回的 Bean 类字段不能直接访问,而应该通过生成 Get 方法,然后使用这个 Get 方法来访问字段。

  • 接口请求成功的提示可以不显示,但请求失败的提示需要显示给到用户,否则会加大排查问题的难度,也极有可能会把问题掩盖掉,从而导致问题遗留到线上去。

  • 如果用的 Json 解析框架是 Gson,则建议进行容错处理,秉持不信任后台的原则,因为我们没有办法控制后台返回了什么数据结构,但是我们有办法保证应用不会为这个问题而导致崩溃。

变量命名规范