本规范基于阿里巴巴《Java开发手册》和 Android 开发最佳实践制定
正例:
class LoginViewModel
class AuthRepository
class UserFragment
反例:
class loginViewModel // ❌ 首字母小写
class Auth_Repository // ❌ 使用下划线
正例:
fun login(mobile: String, password: String)
private val loginState: StateFlow<LoginState>
val userRepository: UserRepository
反例:
fun Login() // ❌ 首字母大写
fun get_user_info() // ❌ 使用下划线
正例:
companion object {
const val MAX_PASSWORD_LENGTH = 16
const val MIN_PASSWORD_LENGTH = 6
const val SUCCESS_CODE = 0
}
反例:
const val maxPasswordLength = 16 // ❌ 应该大写
const val SUCCESS_CODE = 0 // ✅ 正确
const val SuccessCode = 0 // ❌ 应该全大写+下划线
正例:
abstract class BaseViewModel
abstract class BaseRepository
abstract class BaseFragment
反例:
// ❌ 错误示例
if (commonResult.code != 0) { // 魔法数字 0
// ...
}
if (password.length < 4 || password.length > 16) { // 魔法数字 4, 16
// ...
}
正例:
// ✅ 正确示例
object ApiConstants {
/** 成功状态码 */
const val SUCCESS_CODE = 0
}
object ValidationConstants {
/** 密码最小长度 */
const val MIN_PASSWORD_LENGTH = 6
/** 密码最大长度 */
const val MAX_PASSWORD_LENGTH = 16
}
// 使用
if (commonResult.code != ApiConstants.SUCCESS_CODE) {
// ...
}
if (password.length < ValidationConstants.MIN_PASSWORD_LENGTH
|| password.length > ValidationConstants.MAX_PASSWORD_LENGTH) {
// ...
}
目录结构:
module/
├── data/
│ └── constant/
│ └── ApiConstants.kt # API 相关常量
├── domain/
│ └── constant/
│ └── ValidationConstants.kt # 验证相关常量
└── ui/
└── constant/
└── UiConstants.kt # UI 相关常量
示例:
// user/data/constant/ApiConstants.kt
package com.narutohuo.xindazhou.user.data.constant
/**
* API 相关常量
*/
object ApiConstants {
/** 成功状态码 */
const val SUCCESS_CODE = 0
/** 请求超时时间(秒) */
const val TIMEOUT_SECONDS = 30
}
// user/ui/constant/UiConstants.kt
package com.narutohuo.xindazhou.user.ui.constant
/**
* UI 相关常量
*/
object UiConstants {
/** 提示信息 */
const val MSG_MOBILE_EMPTY = "请输入手机号"
const val MSG_PASSWORD_EMPTY = "请输入密码"
const val MSG_LOGIN_SUCCESS = "登录成功"
const val MSG_LOGIN_FAILED = "登录失败"
}
正例:
// 如果大括号内为空,则简洁地写成 {} 即可
fun emptyFunction() {}
// 如果大括号内非空,则:
// 1) 左大括号前不换行
// 2) 左大括号后换行
// 3) 右大括号前换行
// 4) 右大括号后还有 else 等代码则不换行
if (condition) {
statements
} else {
statements
}
超出需要换行,换行时遵循以下原则:
正例:
val result = repository.getUserInfo(mobile = mobile,
password = password,
deviceId = deviceId)
val longString = "这是一个很长的字符串" +
"需要换行显示"
正例:
// 通过类名访问
ApiConstants.SUCCESS_CODE
ValidationConstants.MIN_PASSWORD_LENGTH
反例:
// ❌ 通过实例访问(虽然Kotlin不推荐这样写)
val constants = ApiConstants()
constants.SUCCESS_CODE
示例:
class LoginViewModel(application: Application) : AndroidViewModel(application) {
companion object {
private const val TAG = "LoginViewModel"
}
private val authRepository = AuthRepository()
private val _loginState = MutableStateFlow<LoginState>(LoginState.Idle)
val loginState: StateFlow<LoginState> = _loginState
fun login(mobile: String, password: String) {
// ...
}
private fun validateInput(mobile: String, password: String): Boolean {
// ...
}
}
正例:
data class User(val id: Long, val name: String) {
// data class 会自动生成 equals 和 hashCode
}
正例:
when (state) {
is LoginState.Idle -> { /* ... */ }
is LoginState.Loading -> { /* ... */ }
is LoginState.Success -> { /* ... */ }
is LoginState.Error -> { /* ... */ }
}
说明: 如果并发控制没有处理好,容易产生等值判断被"击穿"的情况,使用大于或小于的区间判断条件来代替。
正例:
/**
* 认证数据仓库
*
* 负责统一管理认证相关的数据获取和缓存
*
* @author YourName
* @date 2024-01-01
*/
class AuthRepository {
/**
* 用户登录
*
* @param mobile 手机号(11位数字)
* @param password 密码(6-16位字符)
* @return Result<LoginResponse> 登录结果,成功包含登录响应数据
*/
suspend fun login(mobile: String, password: String): Result<LoginResponse> {
// ...
}
}
除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。
反例:
catch (e: Exception) {
e.printStackTrace() // ❌ 禁止使用
}
正例:
catch (e: Exception) {
Timber.e(e, "$TAG - login: 登录异常") // ✅ 使用日志框架
}
捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之。
反例:
try {
// ...
} catch (e: Exception) {
// ❌ 空 catch 块
}
正例:
try {
// ...
} catch (e: Exception) {
Timber.e(e, "$TAG - login: 登录异常")
// 记录日志或返回错误结果
return Result.failure(e)
}
Kotlin 安全调用操作符:
反例:
val commonResult = response.body()!! // ❌ 危险的非空断言
正例:
val commonResult = response.body()
?: return Result.failure(Exception("响应体为空"))
// 或者
response.body()?.let { commonResult ->
// 处理逻辑
} ?: run {
return Result.failure(Exception("响应体为空"))
}
正例:
import timber.log.Timber
class AuthRepository {
companion object {
private const val TAG = "AuthRepository"
}
suspend fun login(mobile: String, password: String) {
Timber.d("$TAG - login: 开始登录,mobile=${mobile.take(3)}***")
// ...
Timber.d("$TAG - login: 登录成功")
}
}
反例:
// ❌ 错误:字符串拼接
Timber.d("$TAG - login: mobile=$mobile, password=$password")
正例:
// ✅ 正确:Kotlin 的字符串模板(推荐)
Timber.d("$TAG - login: mobile=${mobile.take(3)}***, passwordLength=${password.length}")
// ✅ 或者使用 Timber 的格式化(推荐用于敏感信息)
Timber.d("$TAG - login: 开始登录")
使用建议:
Timber.d("$TAG - method: 调试信息") // 开发调试
Timber.i("$TAG - method: 重要信息") // 关键业务节点
Timber.w("$TAG - method: 警告信息") // 异常但不影响运行
Timber.e(e, "$TAG - method: 错误信息") // 错误并记录异常
格式:类名 - 方法名: 消息
正例:
Timber.d("$TAG - login: 开始登录")
Timber.d("$TAG - login: 登录成功")
Timber.e(e, "$TAG - login: 登录失败")
反例:
// ❌ 过多装饰符号和emoji
Timber.d("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
Timber.d("📝 [注册] 开始注册请求")
Timber.d("🔐 [注册] 密码长度: ${password.length}")
反例:
Timber.d("$TAG - login: mobile=$mobile, password=$password") // ❌ 密码不应该打印
正例:
Timber.d("$TAG - login: mobile=${mobile.take(3)}***, passwordLength=${password.length}")
包括但不限于:密码、Token、用户个人信息等。
正例:
class LoginFragment : Fragment() {
private var _binding: FragmentLoginBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentLoginBinding.inflate(inflater, container, false)
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
业务逻辑应该放在 ViewModel 或 UseCase 中。
正例:
private val _loginState = MutableStateFlow<LoginState>(LoginState.Idle)
val loginState: StateFlow<LoginState> = _loginState
反例:
Toast.makeText(context, "登录成功", Toast.LENGTH_SHORT).show() // ❌
正例:
// strings.xml
<string name="login_success">登录成功</string>
// Kotlin代码
Toast.makeText(context, getString(R.string.login_success), Toast.LENGTH_SHORT).show()
正例:
val name: String? = getUserName()
name?.let {
println(it.length)
}
!! 非空断言操作符反例:
val result = response.body()!! // ❌ 危险
正例:
val result = response.body() ?: return Result.failure(Exception("响应体为空"))
正例:
suspend fun login(mobile: String, password: String): Result<LoginResponse> {
return withContext(Dispatchers.IO) {
// 网络请求
}
}
正例:
fun login(mobile: String, password: String) {
viewModelScope.launch {
repository.login(mobile, password)
}
}
正例:
data class LoginRequest(
val mobile: String,
val password: String
)
!! 非空断言,已改为安全调用文档版本: v1.0
最后更新: 2024-01-01
维护者: 开发团队