Android 代码规范

99 阅读7分钟

一、代码规范

  • 对于存在多线程访问的业务场景下,必须使用线程安全的容器,例如用ConcurrentHashMap代替HashMap, 用CopyOnWriteArrayList代替ArrayList, CopyOnWriteArrayList代替CopyOnWriteArraySet代替HashSet,StringBuffer代替StringBuilder(),DateTimeFormat代替SimpleDateFormat。

  • 涉及到string和double,int, float等之间转换的时候,用NumberParseUtil.parseInt(String str),NumberParseUtil.parseDouble(String str),NumberParseUtil.parseFloat(String str)等parseXXX(String str)方法。 反例: int value = Integer.parseInt(String str); 正例: int value = NumberParseUtils.parseInt(String str, int defValue);

  • int,long,double,float等基本类型转为String的时候,统一用String.value()的形式,不要用+""、Double.toString()、Integer.toString()的方式(防止手抖写成 " "的形式)。 反例: int value = 1; String valueStr = value + ""; 正例: int value = 1; String valueStr = String.valueOf(1)

  • 判断某个String类型的double值是否等于0,用NumberParseUtils.parseDouble() 反例: String fee = otherFeeBean.getServiceFee(); if ("0".equals(fee) || "0.0".equals(fee) || "0.00".equals(fee)) {     return true; } 正例: if(NumberParseUtils.parseDouble(otherFeeBean.getServiceFee(),0) <= 0) {     return true; }

  • 涉及到非空判断,请用N.isEmpty().(该方法内部会判断空字符串情况) 反例: if (userId == null) { }

    正例: if (N.isEmpty(userId)) { }

  • 判断List的元素个数用CollectionUtils.isEmpty(),不要用list.Size() 反例: if (list.size > 0) { } 反例: if (locationDistricts.isEmpty() { }

  • 正例: if (CollectionUtils.isEmpty(list)) {

    }

  • 所有的字符串资源,必须在strings.xml中定义,不能直接在代码中写死。 反例: ToastUtils.showShort(this, "请选择代收货款选项"); if ("1".equals(payMethod){}

    正例: ToastUtils.showShort(this, R.string.sendex_please_select_cod); if(PayMethodUtil.isSenderXianJiePay(payMethod)){}

  • 能够通过bean.isXX()获取的(类似AddServiceBean.isXXXService()、OfflineTaskBean.isXXXStatus(),

    SimpleTaskBean.isxxxType(),OrderInfoVo.isxxx()接口),不要自己写常量去做equals笔记。

    反例: String status = taskVo.getStatus(); if (TaskConstants.TASK_COMPLETED.equalsIgnoreCase(status)) { } 正例: if(taskVo.isExectuingStatus()){ }

  • 变量与常量做equals比较时,将常量放置在equals前面。 反例: if (mPayMethod.equals(Constants.VALUE.PAY_TYPE_TWO_VALUE)) { } 正例: if (Constants.VALUE.PAY_TYPE_TWO_VALUE.equals(mPayMethod)) { }

  • 启动activity或者fragment时,当传递参数需要超过3个(包括3个),需要定义一个ParamBean来封装参数, 并用静态的 launch()或者launchForResult()方法启动,不要用gotoActivity()、goActivity(),jumpActivity()之类的命名。

  • 实现Parceable接口的bean对象,在添加或者删除属性时,一定要记得用工具重新生成parceable接口实现,,避免出现因为漏掉某个字段的序列胡导致取值失败(不要手写,手写容易写错或泄露某个字段的情况,已出现过生产问题);

  • 实现Serializable或者Parceable接口的对象,如果提供了有参构造方法,一定要实现无参构造方法,否则在将json字符串转换为bean的时候会报错;另外需要注意如果bean中内部还有bean属性,也要实现Serialbible或者Parceablej接口。

  • 实现Serializable或者Parceable接口的对象,对于成员变量,必须提供get和set方法,不能只写get方法,因为涉及到反射,没有set方法会导致反射失败。

  • 不要直接对集合进行遍历,请用增强for。

  • activity跳转的时候,用显示跳转,不要用隐式跳转,Action隐式跳转的时候,需要判断activity是否存在,并做try catch处理。

  • 广播的反注册时,需要自己定义一个变量,在register之后做标记,在反注册的时候判断这个标记,如果确实是注册了才去执行反注册,并且做try catch

  • 打印日志的时候, 不要用ComUserUtils.d("bean = "+ bean)的方式,ComUserUtils.d("bean = %s", bean)的方式,这样在关闭日志开关时,可以减少字符串拼接带来的内存消耗。

  • 不要手动调用生命周期函数

  • RecycleView的item布局最外层不要用android:layout_height="match_parent",应该使用android:layout_height="wrap_content" (appCpmpat版本升级会导致不兼容问题)

  • 在Fragment中,使用getActivity()时要记得判空,防止activity已经回收的情况下导致app崩溃。

  • 获取string、color、drawable等所有资源,都通过ResUtil.getXXX()来获取

  • artemis作为统一的工具类和公共常量入口,不要在用其他的模块的工具方法,如果开发时需要,请将其移到artmis。

  • showDialog的时候,需要先判断dialog != null && !dialog.isShowing(), 否则多次调用代码会出现弹出对个对话框的情况

  • rxjava调用subscribe的onNext时,一定要记得调用onComplete, 不调用onComplete会导致内存泄漏

  • 用!N.isEmtpy(String str)来判断字符串不为空,不要用str != null 或者 TextUtil.isEmpty(String str))来判断(解决空字符串被判断为非空的问题)

  • 判断是纸质单还是电子单,统一用OrderInfoVo中的ELECTRONIC_WAYBILL_INT,不要用ComConstant#Pickup#TYPE_ELEC_WAYBILL或其他硬编码。

  • 判断支付方式的统一用PayMethodConstants中定义的常量,不要定义其他的常量或硬编码。

  • 通过RouteInfo对象中的destinationCityCode(目的地城市代码)判断是否是"香港"、"台湾",”澳门“等流向时,可以直接用RouteInfo.isHkRouteInfo()、RouteInfo.isMcRouteInfo()、RouteInfo.isTwRouteInfo(),不用取出字段去做比较,或者通过mvpb的方式去调用。

  • 通过action隐式启动第三方activity, broadcastRecevier,service等组件的action都统一放到ArtemisConstants→ACTIVITY_ACTION内部类中。

  • 所有新添加的图片必须先通过tinypng网站压缩再放入项目中引用(tinypng.com

  • 所有涉及到从TaskDetailResp中获取某个属性的业务方法,统一放置到TaskDetailFieldUtil中。

  • 跟后台交互的所有字段都建议定为String(String可以兼容int,float,double等其他基本类型),避免出现app端定义为double, 但是服务器端定义为String, 当这个字段返回为 null或者空字符串时,导致整个json字符串反序列化为bean的失败。

  • 用TextWatcher监听EditText输入时,使用SimpleTextWatcher, 只需要选择实现对应的方法(通常只需要监听afterTextChanged()方法,减少代码量), 如果需要延迟执行afterTextChanged(),应该使用SimpleDelayTextWatcher(解决频繁调用afterTextChanged()查库或者调用在线接口时,******** 性能损耗和数据错乱问题(前一次调用结果用的是后一次调用返回的数据问题)。

  • 使用RxJava的时候,调用了subscribe.onNext(),一定要调用subscribe.onComplete(),否则会有内存泄漏风险

  • 跟后台定义接口时,涉及到日期的,统一用时间戳表示,不要用Date类型。因为Json本身没有Data类型,序列化的时候Json库会将Date类型的数据序列化会转换为String,不同环境不同平台以及不同的Json解析类库,转换后的结果经常会不同,例如在开发机上可能得到的结果是 “2019-1-1 13:43:11”,在服务器端解析的结果却是“Jan 1,2019 1:43:11 PM”,客户端进行反序列化时就会失败。

  • 涉及到调用后台接口的,如果涉及到某些条件才会调用或者不调用的,一定要详细记录各个步骤的参数并且用日志打印出来,方便定位生产问题。

  • 凡是涉及到调用后台接口的,一定要考虑接口调用失败的场景下,如果处理。

  • 费用计算用 bigdeciamal解决精度丢失问题

代码风格

  • 变量/常量定义原则: 常量默认统一用private static final修饰,如果需要多个类访问同一个常量时,才考虑扩大修饰符范围为protected 或者 public

  • 代码风格:统一采用fxgCodeStyle模板,项目doc目录下。配置方法: studio-preferences-editor-code style-java-import

  • 能用非静态变量就不要定义静态变量;能用局部变量,就不要用全局成员变量。

  • 代码风格:统一采用fxgCodeStyle模板,项目doc目录下。配置方法: studio-preferences-editor-code style-java-import

  • 注释了的类,淘汰了的代码在开发时顺手删除。

  • if-else单个方法不要超过三层,非空判断在外层就必须做好。

  • 在Activiyt,Fragment等UI视图中,仅做页面展示逻辑,不要把处理业务逻辑的代码放到这里面,数据处理等业务逻辑可以放到P层或B层处理。

  • 注释了的类,淘汰了的代码在开发时顺手删除。

  • 所有实体bean必须添加注释说明。