# 开发规范

# 工程结构

  • 包分层结构

    ├── 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

  • 类和接口名:大驼峰

    ModelOnClickListener

  • 文件名:大驼峰

    LoginActivity.kt

  • 变量名和运行期常量名:小驼峰

    productNamepartnerMode

  • 编译期常量名:全大写,可以用下划线隔开

    YEARWEEK_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_enabledstate_pressedstate_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

# 编码规范

  1. 字段的可空性 ?.,避免后端数据异常抛出空指针异常
val user:User? = null
//使用null安全调用 ?.
user?.userAvatar
  1. 变量初始化可使用懒加载方式,如Intent参数的获取:
/**
 * 申请ID
 */
private val applyId by lazy {
   intent.getLongExtra(KEY_AUDIT_ID, 0)
}
  1. 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的逻辑代码做到最少化,由ViewModelPresenter层来实现,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:armeabiarmeabi-v7ax86mipsarm64- v8amips64x86_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'
最后更新时间: 11/24/2021, 1:59:05 AM