安卓项目规范

Android项目规范

命名规范

通用命名规范

  1. 如果模块、接口、类、方法使用了设计模式,在命名时需体现出具体模式。(Builder、Factory、Proxy、Adapter、Wrapper)
  2. 任何命名不能以下划线或者符号开头。
  3. 任何命名严禁直接使用中文的方式。纯拼音的方式应尽量避免使用,使用完整的单词组合来表达其意。
  4. 杜绝完全不规范的缩写,避免望文不知义(多个单词缩写不要只提取首字母)。

包命名规范

  1. 反域名命名规则
  2. .之间有且仅有一个自然语义的英语单词,可以使用下划线。

类,抽象类,接口命名规范

  1. 名词
  2. 类名使用UpperCamelCase(大驼峰)风格
  3. 抽象类命名使用 AbstractBase 开头
  4. 接口类命名使用以listener,able,ible,callback等类似功能性词缀结尾(单独文件时使用,变量命名则遵循变量名规范)
  5. 异常类命名使用ExceptionThrowable结尾。
  6. 测试类命名以要测试的类的名称开始,以Test结尾
  7. dataClass后缀为Bean
  8. 枚举类后缀为Enum
  9. 数据库的数据类后缀为Entity
  10. dataClass进行类转换或者提取信息的工具类后缀为Converter

函数命名规范

  1. 动词或动名词
  2. 方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase(小驼峰)风格

变量命名规范

  1. 不允许任何魔法值(即未经预先定义的常量)直接出现在代码中。(单个文件内的boolean、int类型可以使用,加上注释,但是不建议)
  2. 在 long 或者 Long 赋值时,数值后使用大写的 L,不能是小写的 l,小写容易跟数字1 混淆,造成误解。
  3. 不要使用一个常量类维护所有常量,要按常量功能进行归类,分开维护。
  4. 如果变量值仅在一个固定范围内变化用 enum 类型来定义。
  5. 枚举成员名称需要全大写,单词间用下划线隔开。
  6. 类中控件名称尽量和xml控件id保持一致
  7. 公开常量应定义为静态final,名称全部大写.
    例如: ```const val ACTION_MAIN = ”android.intent.action.MAIN”``

安卓相关命名规范

Java类命名

格式 示例
Activity xxx描述+Activity FindActivity
Fragment xxx描述+Fragment SearchFragment
Adapter xxx描述+Adapter SearchAdapter
Model xxx描述+Model SearchModel
ViewModel xxx描述+ViewModel SearchViewModel
Service xxx描述+Service ImService
BroadcastReceiver xxx描述+Receiver NetworkReceiver
基类 Base+父类命名 BaseActivity

资源文件命名规范

  • 命名以使用的控件为前缀,后面加上描述,中间以下划线分隔
  • lib库的资源在以上基础上加上模块前缀,防止资源名称相同编译不通过

控件命名

控件 缩写
TextView tv
EditText et
Button bt
ImageButton ib
LinearLayout ll
RelativeLayout rl
RecyclerView rv
ScrollView sv
ConstraintLayout cl
  1. layout
布局类型 命名格式
Activity布局 module_activity_xxx
fragment布局 module_fragment_xxx
dialog布局 module_dialog_xxx
可include布局 module_include_xxx
recyclerView布局 module_recycler_item_xxx

drawable

drawable 命名格式
icon module_ic_xxx
selector module_selector_xxx
shape module_shape_xxx
menu module_menu_xxx
selector
  • 多状态的,应在命名中体现
selector 命名格式
normal xx_normal
pressed xx_pressed
focused xx_focused
selected xx_selected

strings

  • strings 见名知意即可

colors

dimens

  • length_value 代表一般长度(暂时用不到)
  • font_value 代表字体
  • (UI规范类的暂时没有)

控件ID

控件名+功能(全称也行)

控件 缩写
LinearLayout ll
RelativeLayout rl
TextView tv
Button bt
ImageButton iv
ImageView iv
CheckBox cb
RadioButton rb
DatePicker dp
EditText et
TimePicker tp
ProgressBar pb
SeekBar sb
AutoCompleteTextView actv
ZoomControls zc
VideoView vv
WdbView wv
RantingBar rb
Tab tab
Spinner spn
Chronometer cmt
ScrollView sv
TextSwitch ts
ImageSwitch is
listView lv
ExpandableList el
MapView mapView

编码要求

通用编码要求

  1. 代码格式化用开发工具默认的风格
  2. 单个方法的总行数尽量不超过 100 行
  3. 不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来以提升可读性。任何情形,没有必要插入多个空行进行隔开。
  4. 过时的类和方法必须加@Deprecated 注解.(kotlin怎么处理需要再看一下,禁用官方已经Deprecated的类和方法,除非低版本适配)
  5. 类内方法定义的顺序依次是:功能相近活着引用的方法放到一起。
  6. 避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可。
  7. 避免黄色警告。
  8. 每一个module都要有自己的README.md文件。

Kotlin相关编码要求

  1. 在一个 when 块内,都必须包含一个 else 语句并且放在最后,即使空代码。
  2. 多个字符串动态拼接的时候,使用StringBuilder 的 append 方法进行扩展。避免造成内存资源浪费。

类成员与方法访问控制

  1. 如果不允许外部直接通过 new 来创建对象,那么构造方法必须是 private
  2. 工具类不允许有 publicdefault 构造方法,禁用Utils,要使用Ext,Converter,顶层声明
  3. 类非 static 成员变量并且与子类共享,必须是 protected
  4. 类非 static 成员变量并且仅在本类使用,必须是 private
  5. static 成员变量如果仅在本类使用,必须是 private
  6. 若是 static 成员变量,考虑是否为 const val
  7. 类成员方法只供类内部调用,必须是 private
  8. 类成员方法只对继承类公开,那么限制为 open

注释规范

  1. 类、类属性、类方法的注释必须使用 Javadoc 规范,使用/**内容*/格式,不得使用// xxx方式。
  2. 所有的抽象方法(包括接口中的方法)必须要用 Javadoc 注释,指出该方法做什么事情,实现什么功能。
  3. 所有的类都必须添加创建者和创建日期和功能.
  4. 方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用/* */注释
  5. 所有的枚举类型字段必须要有注释,说明每个数据项的用途。
  6. 注释中专有名词与关键字保持英文原文即可。
  7. 修改代码时也应该同步修改注释

注释模板

  • 统一修改成以下注释模版,在创建文件时必须加上这个
    1
    2
    3
    4
    5
    6
    /**
    * @Description: TODO
    * @Author: ${USER}
    * @Date: ${DATE} ${TIME}
    * @Gmail: 你的这个邮箱 @tron.network
    */

Android相关编码要求(优化项)

  1. 避免在 Service#onStartCommand()/onBind()方法中执行耗时操作,如果确实有需求,应改用 IntentService 或采用其他异步机制完成。
  2. 避免在 BroadcastReceiver#onReceive()中执行耗时操作,如果有耗时工作,应该创建 IntentService 完成,而不应该在 BroadcastReceiver 内创建子线程去做。
  3. 对于只用于应用内的广播,优先使用 LocalBroadcastManager 来进行注册和发送,LocalBroadcastManager 安全性更好,同时拥有更高的运行效率。
  4. Activity或者 Fragment 中动态注册BroadCastReceiver 时,registerReceiver()unregisterReceiver()要成对出现。
  5. 释放资源的实际可以结合实际情况在onStop执行,在Ondestroy中执行时机比较晚
  6. 源文件统一采用 UTF-8 的形式进行编码。
  7. 禁止在设计布局时多次设置子 view 和父 view 中为同样的背景造成页面过度绘制,推荐将不需要显示的布局进行及时隐藏,推荐使用约束布局
  8. 文本大小使用单位 spview 大小使用单位 dp
  9. 尽少使用 AnimationDrawable 会把所有图片都加载到内存,注意内存溢出
  10. 子线程中不能更新界面,更新界面必须在主线程中进行,网络操作不能在主线程中调用。
  11. 新建线程时,定义能识别自己业务的线程名称,便于性能优化和问题排查。
  12. 任何时候不要硬编码文件路径,请使用 Android 文件系统 API 访问。
  13. 当使用外部存储时,必须检查外部存储的可用性。
  14. 应用间共享文件时,不要通过放宽文件系统权限的方式去实现,而应使用FileProvider
  15. SharedPreference 中只能存储简单数据类型(intbooleanString 等),复杂数据类型建议使用数据库等其他方式存储。
  16. 数据库 Cursor 必须确保使用完后关闭,以免内存泄漏。
  17. 多线程操作写入数据库时,需要使用事务,以免出现同步问题。
  18. Activity.onPause()Activity.onStop()回调中,关闭当前 activity 正在执行的的动画。
  19. 在有强依赖 onAnimationEnd 回调的交互时,如动画播放完毕才能操作页面 ,onAnimationEnd可能会因各种异常没被回调,建议加上超时保护或通过postDelay替代onAnimationEnd
  20. android:allowbackup 属性设置为 false,防止 adb backup 导出数据。
  21. 应用发布前确保 android:debuggable 属性设置为 false。

其他编码要求

  1. 砍掉的需求和无用代码以及注释必须及时清除
  2. 一些空指针异常不要用try catch
  3. 应用中不允许直接调用系统的类打印日志
  4. 正式环境禁止输出日志
  5. 严格按照MVVM模型开发
  6. 使用响应式编程范式开发
  7. 使用第三方SDK的时候 应避免直接依赖 需要写一层中间件(除了长期不变的主流框架不需要写中间件)

关于序列化

  1. 如果是持久化保存用Serializable序列化
  2. 如果是只是在内存中使用 用Parcelable序列化

关于单例模式

  1. 注意是否有高并发

代码检查

  1. 类,抽象类,接口,泛型必须要按照注释模版进行注释
    没有注释的不予通过.
  2. 拼写错误必须处理 typo
  3. TODO

代码规范写法,否则会有@SuppressLint警告

@SuppressLint(“DrawAllocation”)

原因:我们都知道View及其子类的OnDraw(Canvas canvas)方法会实时调用来更新界面的,然而有时我们会在onDraw(Canvas canvas)方法中实例化对象(如Paint paint=new Paint()),这样就会影响我们程序的效率。
解决办法:将这些对象改为类的成员变量。

@SuppressWarnings(“rawtypes”)和@SuppressWarnings({ “unchecked”, “rawtypes” })

不规范写法:

1
Class clazz = Class.forName(“android.view.Display”); 

正确写法:

1
Class<?> clazz = Class.forName("android.view.Display");

@SuppressLint(“HandlerLeak”)

原因:Handler在Android中用于消息的发送与异步处理,常常在Activity中作为一个匿名内部类来定义,此时Handler会隐式地持有一个外部类对象(通常是一个Activity)的引用。当Activity已经被用户关闭时,由于Handler持有Activity的引用造成Activity无法被GC回收,这样容易造成内存泄露。
解决办法:将其定义成一个静态内部类(此时不会持有外部类对象的引用),在构造方法中传入Activity并对Activity对象增加一个弱引用,这样Activity被用户关闭之后,即便异步消息还未处理完毕,Activity也能够被GC回收,从而避免了内存泄露。

静态内部类,持有外部类的弱引用。这是最标准的写法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private MyHandler handler = new MyHandler(this);
static class MyHandler extends Handler {
private WeakReference<Activity> weakReference;
public MyHandler(SecondActivity activity) {
weakReference = new WeakReference<Activity>(activity);
}

@Override
public void handleMessage(Message msg) {
if (reference.get() != null) {
switch (msg.what) {
case 0:
// do something...
break;
default:
// do something...
break;
}
}
}
}

另一种情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//不规范的写法
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg){
};
};

//正确的写法
private Handler mHandler = new Handler(new Handler.Callback(){
@Override
public boolean handleMessage(Message msg){
return false;
}
});

@SuppressLint(“SimpleDateFormat”)

不规范写法:

1
SimpleDateFormat format = new SimpleDateFormat(pattern); 

正确写法:

1
SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.getDefault());

@SuppressLint(“DefaultLocale”)

不规范写法:

1
2
String lower = string.toLowerCase(); 
boolean b = “String”.toUpperCase().equals(“STRING”);

正确写法:

1
2
String lower = string.toLowerCase(Locale.getDefault()); 
boolean b = “String”.toUpperCase().equals(“STRING”);