# 开发规范
# 工程结构
包分层结构
├── app ├── common_base // 项目基础类(如.框架基础、网络请求、工具类等) ├── common_business // 项目通用业务(如.登陆、下载、支付、分享、推送等) ├── common_ui // 放置基础组件(如.自定义组件View、Dialog等) ├── module_partner // 具体业务模块 ├── gradle.properties ...
资源Resource
res ├── anim // 定义渐变动画资源 ├── color // 定义颜色状态资源 ├── drawable// 位图资源(.png、.9.png、.jpg、.gif) ├── layout // 定义用户界面布局 ├── menu // 用于定义应用菜单 ├── mipmap // 适配不同分辨率App图标 ├── values // 数据值(styles/attrs样式、colors、dimens、strings/arrays) ├── raw // 原始形式保存的任意文件 └── xml // 在运行时通过调用 Resources.getXML() 读取的任意 XML 文件
# 命名规范
# 基础命名
大部分适用驼峰 UpperCamelCase
风格
包名:全小写,中间点分隔开
com.mmm.partner
类和接口名:大驼峰
Model
、OnClickListener
文件名:大驼峰
LoginActivity.kt
变量名和运行期常量名:小驼峰
productName
、partnerMode
编译期常量名:全大写,可以用下划线隔开
YEAR
、WEEK_OF_MONTH
函数名:小驼峰,动词或动词+名词;
getName()
、onResume()
、removeData()
而不是dataRemove()
# 基础类文件
类 | 描述 | 示例 |
---|---|---|
Activity | 模块 + Activity | SplashActivity |
Fragment | 模块 + Fragment | EnterpriseFragment |
Dialog | 功能 + Dialog | UpgradeDialog |
PopupWindow | 功能 + Popwnd | SelectAreaPopWnd |
自定义控件 | 自定义 + View | DotView |
扩展控件 | 功能 + View | LoadMoreRecyclerView |
列表适配器 | 功能 + Adapter | ProductRankAdapter |
ViewModel | 功能 + ViewModel | EnterpriseViewModel |
Utils | 功能 + Utils | TimeUtils |
# 资源命名
# 布局文件
类 | 描述 | 布局资源 |
---|---|---|
Activity | SplashActivity | activity_splash.xml |
Fragment | EnterpriseFragment | fragment_enterprise.xml |
Dialog | UpgradeDialog | dialog_upgrade.xml |
PopupWindow | SelectAreaPopWnd | popwnd_select_area.xml |
Adapter | ProductRankAdapter | item_product_rank.xml |
# 控件ID
以 控件简写 + 功能 组合进行命名
var Button btnSubmit
var TextView tvTitle
var ImageView ivProfile
控件 | 简写 |
---|---|
TextView | tv |
EditText | et |
Button | btn |
ImageView | iv |
RecyclerView | rv |
ScrollView | sv |
FrameLayout | fl |
LinearLayout | ll |
RelativeLayout | rl |
ConstraintLayout | cl |
... |
# 图片资源
背景资源bg_xxx、普通图标ic_xxx; 如. bg_search、ic_back
<!-- 背景资源命名、图标命名 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_search"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_back" />
</LinearLayout>
# 颜色定义
美工提供色卡图编号统一命名,按color1,color2,color3...;
<!-- 字体颜色引用1号色卡、背景引用2号色卡 -->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/color1"
android:background="@color/color2">
</TextView>
# 图形形状
shape
命名规则,主要以弧度、主颜色、描边颜色为文件定义命名
<!-- 矩形shape="rectangle":corners弧度、solid主色、stroke描边 (gradient渐变不在考虑范围) -->
<!-- 1.XML命名:r0001_s01_s00.xml -->
<shape android:shape="rectangle">
<solid android:color="@color/color1"/>
</shape>
<!-- 2.XML命名:r1501_s01_s00.xml -->
<shape android:shape="rectangle">
<corners android:radius="15dp" />
<solid android:color="@color/color1"/>
</shape>
<!-- 3.XML命名:r1502_s01_s02.xml -->
<shape android:shape="rectangle">
<corners android:radius="15dp" />
<solid android:color="@color/color1"/>
<stroke android:color="@color/color2" android:width="1dp" />
</shape>
<!-- 替换成圆形shape="oval":solid主色、stroke描边 (gradient渐变不在考虑范围) -->
<!-- 1.XML命名:o01_s01_s00.xml -->
<!-- 2.XML命名:o02_s01_s00.xml -->
<!-- 3.XML命名:o03_s01_s02.xml -->
# 状态选择器
selector
不同状态下命名规则,以具体状态 state_enabled
、state_pressed
、state_selected
为命名开头,配合颜色索引或资源编码进行命名,避免资源二次定义;
<!-- 常规全量选择器,常规状态(禁用、选中、按压、焦点等) -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/color1" android:state_enabled="true" />
<item android:color="@color/color2" android:state_pressed="true" />
<item android:color="@color/color3" android:state_selected="true" />
<item android:color="@color/color4" />
</selector>
<!-- 状态:禁用/启用 XML命名: state_enabled_c4_c1.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/color1" android:state_enabled="true" />
<item android:color="@color/color4" />
</selector>
<!-- 状态:按压/默认 XML命名: state_selected_c4_c2.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/color2" android:state_pressed="true" />
<item android:color="@color/color4" />
</selector>
<!-- 状态:选中/未选 XML命名: state_selected_c4_c3.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/color3" android:state_selected="true" />
<item android:color="@color/color4" />
</selector>
<!-- 自定义形状资源:选中/未选 XML命名: state_selected_r1501_r1502.xml(以此类推不同的状态命名规则) -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@drawable/r1502_s01_s02" android:state_selected="true" />
<item android:color="@drawable/r1501_s01_s00" />
</selector>
<!-- 字体颜色、背景资源 在未选/选中状态的变更-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/state_selected_c4_c10"
android:background="@drawable/state_selected_r1501_r1502">
</TextView>
# 注释规范
- 合理的注释,可以提高代码的可读性和可维护性
- 如无必要,勿增注释,应当追求「代码自注释」
- 如有必要,尽量详尽,需要注释的地方应该尽量详尽地去写
- 遵循统一的风格规范,如一定的空格、空行,以保证注释自身的可读性
3.1 类注释 在AS里进行配置,作者及时间等相关信息,对自己编写的代码负责,配置方式如下
Settings -> Editor -> File and Code Templates -> Includes -> File Header
3.2 变量、方法注释
- 单行注释使用
//
注释行的上方需要有一个空行;注释内容和注释符之间需要有一个空格 - 多行注释使用
/** ... */
3.3 注释中的变量和引用 Java使用 javadoc 标记(@return
@param
...) ,kotlin推荐统一使用 [ ]
以下是示例:
/**
* created by cwzqf on 2021/7/12
* 共创审核
*/
class ProjectAuditActivity : BaseBusinessActivity() {
/**
* 当前选择的tab索引
*/
private var currentTabIndex = 0
/**
* 上传本地图片,[viewModel] 表示当前对应 ProjectAuditViewModel
*/
private fun uploadPictureIfExist() {
val localPicture = binding.selectLayout.getLocalPicture()
if (localPicture.isNotEmpty()) {
// 上传本地图片
viewModel.requestUploadFiles(localPicture)
} else {
// 无本地图,直接发布项目
collectInputData()
}
}
}
# 样式规范
# 行长设置
代码中每一行文本的长度可以设置长一些,建议 160~180
打开Android Studio,Settings -> Editor -> Code Style -> Kotlin/Java 设置Hard wrap at:170
# 编码规范
- 字段的可空性
?.
,避免后端数据异常抛出空指针异常
val user:User? = null
//使用null安全调用 ?.
user?.userAvatar
- 变量初始化可使用懒加载方式,如Intent参数的获取:
/**
* 申请ID
*/
private val applyId by lazy {
intent.getLongExtra(KEY_AUDIT_ID, 0)
}
- Activity/Fragment 跳转约定
companion object{
const val KEY_COMPANY = "KEY_COMPANY"
const val KEY_TAB_TYPE = "KEY_TAB_TYPE"
const val KEY_COMPANY_ID = "KEY_COMPANY_ID"
//跳转Activity 示例
fun open(context: Context, company: Company? = null) {
context.startActivity<ContractDividendActivity>(KEY_COMPANY to company)
}
//跳转Fragment 示例
fun newInstance(tab:Int, companyId:Int): ContractDividendFragment {
val args = Bundle()
args.putInt(KEY_TAB_TYPE, tab)
args.putInt(KEY_COMPANY_ID, companyId)
val fragment = ContractDividendFragment()
fragment.arguments = args
return fragment
}
}
# 整洁代码建议
- 同一段代码出现两次及以上,应该抽取出该函数
- 类应该足够小,
Activity
/Fragment
的逻辑代码做到最少化,由ViewModel
或Presenter
层来实现,View
层仅仅接收数据改变并相应更新界面 - 函数方法尽可能小,控制在20行以内,函数越小,功能越集中,越便于取一个好名字
- 参数尽量少,最好不要超过3个,除非特殊需求
- 布局重用之
include
,若控件多处样式一致,应抽取出style
# 版本管理规范
软件版本号的形式 major
.minor
.maintenance
.build
// 定义版本号
ext {
major = 1 // 主版本号
minor = 0 // 次版本号
maintenance = 0 // 维护版本号
build = 0 // 构建版本号
// 计算规则
versionCode = major * 1000000 + minor * 10000 + maintenance * 100 + build
versionName = major + "." + minor + "." + maintenance
}
defaultConfig {
// 引用定义的变量
versionCode this.ext.versionCode // 只能递增,最大值2100000000
versionName this.ext.versionName // 显示版本号 1.0.0
...
}
# 第三方SDK
网易云信、百度/高德地图、个推、友盟、科大讯飞等
# ABI引用
全称:Application binary interface(应用程序二进制接口),不同的Android手机使用不同的CPU,因此需要提供对应的二进制接口交互规则;
每个CPU架构对应一个ABI:
armeabi
,armeabi-v7a
,x86
,mips
,arm64- v8a
,mips64
,x86_64
导入
.so
文件时需要注意,引用的CPU架构必须相同 CPU ABI详解 (opens new window)... // 过滤掉x86, mips的so库,保证工程下支持的CPU架构以及第三方提供的不同架构的so文件,最后统一只保留armeabi和armeabi-v7a,避免不同的库缺失抛出异常 ndk { abiFilters "armeabi", "armeabi-v7a", }
# 数据验证
严格遵守公司对第三方账号的管理流程
- 开发者在使用时必须遵循测试环境数据验证规则,申请验证的应用ID,避免脏数据影响到对外用户
- 二次开发时,需要记录修改并提供文档
# 第三方组件
集成第三方框架或者 SDK,需注明作用和出处,以便出现问题时能够快速核查和反馈
第三方库的选择原则:成熟框架,作者持续维护,作者对issue的解决积极度,项目的star数等
使用第三方库必须要依赖指定的版本号,而不能使用 + 号来指定依赖库最新的版本号
// MMKV(微信高性能通用key-value,用来替换SharedPreferences)
implementation 'com.tencent:mmkv-static:1.2.9'
// Arouter(阿里路由框架,支持各种丰富的跳转方案)
implementation 'com.alibaba:arouter-api:1.4.1'
kapt 'com.alibaba:arouter-compiler:1.2.2'
← Android 端 Kotlin编码规范 →