Android 开发规范指南实战教程
还在为Android项目代码风格混乱、架构不清晰而烦恼吗?本文将为你提供一套完整的Android开发规范实战指南,涵盖项目结构、代码风格、架构设计等核心内容,助你打造高质量、易维护的Android应用。
📋 文章内容概览
读完本文你将掌握:
- Android项目标准化结构设计
- Java代码规范与最佳实践
- XML资源文件命名规范
- MVP架构模式实战应用
- 单元测试与Espresso测试规范
- 异常处理与日志管理策略
🏗️ 项目结构规范
标准Gradle项目结构
遵循Android Gradle插件定义的标准项目结构:
app/
├── src/
│ ├── main/
│ │ ├── java/com/yourapp/
│ │ ├── res/
│ │ │ ├── drawable/
│ │ │ ├── layout/
│ │ │ ├── menu/
│ │ │ └── values/
│ │ └── AndroidManifest.xml
│ └── androidTest/java/com/yourapp/
└── build.gradle
文件命名规范
类文件命名
类名采用UpperCamelCase(大驼峰命名法),继承Android组件的类应以组件名结尾:
// Good examples
SignInActivity
UserProfileFragment
ImageUploadService
ChangePasswordDialog
// Bad examples
signin_activity // 不使用下划线
userProfileFrag // 不完整的组件名
资源文件命名
资源文件采用lowercase_underscore(小写下划线命名法):
| 资源类型 | 命名规则 | 示例 |
|---|---|---|
| 布局文件 | 组件类型_描述 | activity_main.xml |
| 菜单文件 | 组件名 | activity_user.xml |
| 值文件 | 复数形式 | strings.xml, styles.xml |
🎨 代码风格规范
字段定义与命名
public class MyClass {
// 常量:ALL_CAPS_WITH_UNDERSCORES
public static final int MAX_RETRY_COUNT = 3;
// 公有字段:小写字母开头
public int publicField;
// 私有静态字段:s前缀
private static MyClass sInstance;
// 私有非静态字段:m前缀
private int mPrivateField;
// 包内可见字段:m前缀
int mPackagePrivateField;
}
缩进与括号风格
使用4空格缩进,括号与代码同行:
// 正确的缩进和括号风格
if (condition) {
executeMethod();
} else {
handleAlternative();
}
// 单行语句可不加括号(仅当条件体和语句能在一行内)
if (condition) doSomething();
// 错误的风格
if (condition)
doSomething(); // 缺少括号,易出错
导入语句排序
导入语句按以下顺序分组,每组间空一行:
- Android imports
- 第三方库 imports (com, junit, net, org)
- java 和 javax imports
- 同项目 imports
// Android imports
import android.app.Activity;
import android.os.Bundle;
// 第三方库
import com.squareup.retrofit2.Retrofit;
// Java标准库
import java.util.List;
import javax.inject.Inject;
// 同项目
import com.yourapp.utils.StringUtils;
📊 资源命名详细规范
Drawable资源命名
| 资源类型 | 前缀 | 示例 |
|---|---|---|
| 图标 | ic_ | ic_star.png |
| 启动图标 | ic_launcher | ic_launcher_app.png |
| 菜单图标 | ic_menu | ic_menu_settings.png |
| 按钮 | btn_ | btn_submit_normal.9.png |
| 对话框 | dialog_ | dialog_background.9.png |
选择器状态后缀
| 状态 | 后缀 | 示例 |
|---|---|---|
| 正常 | _normal | btn_login_normal.png |
| 按下 | _pressed | btn_login_pressed.png |
| 聚焦 | _focused | btn_login_focused.png |
| 禁用 | _disabled | btn_login_disabled.png |
布局文件命名规范
| 组件 | 类名 | 布局文件名 |
|---|---|---|
| Activity | UserProfileActivity | activity_user_profile.xml |
| Fragment | SignUpFragment | fragment_sign_up.xml |
| Dialog | ChangePasswordDialog | dialog_change_password.xml |
| 列表项 | - | item_user.xml |
| 部分布局 | - | partial_header.xml |
🏛️ MVP架构实战
架构组件关系图
各层职责说明
View层(UI层)
- Activities、Fragments等Android标准组件
- 负责显示Presenter提供的数据
- 处理用户交互事件
- 调用Presenter的相应方法
Presenter层
- 订阅DataManager提供的Observables
- 处理订阅生命周期
- 分析/修改DataManager返回的数据
- 调用View的适当方法显示数据
Model层(数据层)
- 负责数据的检索、保存、缓存和处理
- 与本地数据库和API通信
- 包含Helpers和DataManager
DataManager实现示例
public class UserDataManager {
private final DatabaseHelper mDatabaseHelper;
private final PreferencesHelper mPreferencesHelper;
private final UserService mUserService;
public Observable<User> getUserProfile(int userId) {
return mDatabaseHelper.getUser(userId)
.switchIfEmpty(mUserService.getUser(userId)
.doOnNext(user -> mDatabaseHelper.saveUser(user)))
.doOnNext(user -> mPreferencesHelper.saveLastSeenUser(user));
}
}
Presenter实现示例
public class UserProfilePresenter {
private final UserDataManager mDataManager;
private UserProfileView mView;
public void loadUserProfile(int userId) {
mDataManager.getUserProfile(userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(user -> mView.displayUser(user),
error -> mView.showError("加载用户信息失败"));
}
}
🐛 异常处理与日志规范
异常处理最佳实践
// 错误做法:忽略异常
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) {
// 绝对不要忽略异常!
}
}
// 正确做法:适当处理异常
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) {
Log.w(TAG, "无效的端口号: " + value);
serverPort = DEFAULT_PORT; // 提供默认值
}
}
日志管理规范
使用类名作为TAG,并定义为静态final字段:
public class UserActivity extends Activity {
private static final String TAG = UserActivity.class.getSimpleName();
private void loadData() {
if (BuildConfig.DEBUG) {
Log.d(TAG, "开始加载用户数据");
}
try {
// 业务逻辑
Log.i(TAG, "数据加载成功");
} catch (Exception e) {
Log.e(TAG, "数据加载失败", e);
}
}
}
日志级别使用指南
| 级别 | 使用场景 | 发布版本处理 |
|---|---|---|
| VERBOSE | 详细调试信息 | 必须禁用 |
| DEBUG | 调试信息 | 必须禁用 |
| INFO | 普通信息 | 建议禁用 |
| WARN | 警告信息 | 可保留 |
| ERROR | 错误信息 | 可保留 |
🧪 测试规范
单元测试命名规范
测试类名:被测试类名 + Test 测试方法名:methodName + Precondition + ExpectedBehaviour
public class DatabaseHelperTest {
@Test
void getUserWithInvalidIdReturnsEmpty() {
// 测试逻辑
}
@Test
void saveUserWithValidDataSucceeds() {
// 测试逻辑
}
}
Espresso测试规范
public class LoginActivityTest {
@Test
void loginWithValidCredentialsSucceeds() {
onView(withId(R.id.edit_text_email))
.perform(typeText("test@example.com"));
onView(withId(R.id.edit_text_password))
.perform(typeText("password123"));
onView(withId(R.id.button_login))
.perform(click());
onView(withId(R.id.text_view_welcome))
.check(matches(withText("欢迎回来!")));
}
}
📝 代码组织与排序
类成员排序建议
public class MainActivity extends Activity {
// 1. 常量
private static final String TAG = "MainActivity";
public static final int REQUEST_CODE = 1001;
// 2. 字段
private String mUserName;
private TextView mTextViewTitle;
// 3. 构造函数
public MainActivity() {}
// 4. 生命周期方法(按生命周期顺序)
@Override
protected void onCreate(Bundle savedInstanceState) {}
@Override
protected void onStart() {}
@Override
protected void onResume() {}
// 5. 重写方法和回调
@Override
public void onBackPressed() {}
// 6. 公有方法
public void updateUserProfile(User user) {}
// 7. 私有方法
private void initializeViews() {}
// 8. 内部类和接口
interface OnUserClickListener {}
}
方法参数顺序规范
// Context总是第一个参数
public User loadUser(Context context, int userId);
// 回调接口总是最后一个参数
public void loadUserAsync(Context context, int userId, UserCallback callback);
// Intent和Bundle的键常量命名
static final String EXTRA_USER_ID = "com.yourapp.extra.USER_ID";
static final String ARGUMENT_USER_NAME = "ARGUMENT_USER_NAME";
🔧 实用工具与技巧
RxJava链式调用样式
public Observable<List<User>> searchUsers(String query) {
return mDatabaseHelper.searchUsers(query)
.filter(users -> !users.isEmpty())
.switchIfEmpty(mApiService.searchUsers(query)
.doOnNext(users -> mDatabaseHelper.saveUsers(users)))
.retryWhen(errors -> errors.flatMap(error -> {
if (error instanceof NetworkError) {
return Observable.timer(5, TimeUnit.SECONDS);
}
return Observable.error(error);
}))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
字符串常量管理
public class IntentConstants {
private IntentConstants() {} // 防止实例化
// Intent Extra前缀
public static final String EXTRA_USER = "com.yourapp.extra.USER";
public static final String EXTRA_EMAIL = "com.yourapp.extra.EMAIL";
// Bundle参数前缀
public static final String ARGUMENT_USER_ID = "ARGUMENT_USER_ID";
public static final String ARGUMENT_CATEGORY = "ARGUMENT_CATEGORY";
// SharedPreferences前缀
public static final String PREF_USER_TOKEN = "PREF_USER_TOKEN";
public static final String PREF_LAST_LOGIN = "PREF_LAST_LOGIN";
}
🚀 性能优化建议
内存泄漏预防
public class MainActivity extends Activity {
private Subscription mSubscription;
@Override
protected void onResume() {
super.onResume();
mSubscription = mDataManager.getData()
.subscribe(data -> updateUI(data));
}
@Override
protected void onPause() {
super.onPause();
if (mSubscription != null && !mSubscription.isUnsubscribed()) {
mSubscription.unsubscribe();
}
}
}
视图绑定优化
// 使用ViewHolder模式优化列表性能
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.ViewHolder> {
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView nameTextView;
ImageView avatarImageView;
public ViewHolder(View itemView) {
super(itemView);
nameTextView = itemView.findViewById(R.id.text_name);
avatarImageView = itemView.findViewById(R.id.image_avatar);
}
}
}
📋 总结检查清单
代码规范检查项
- 类名使用UpperCamelCase
- 资源文件使用lowercase_underscore
- 字段命名遵循m/s前缀规范
- 导入语句正确分组排序
- 异常处理得当,不忽略异常
- 日志输出在发布版本中适当禁用
架构规范检查项
- 遵循MVP架构分层
- DataManager正确组合Helpers功能
- Presenter处理业务逻辑,不包含Android相关代码
- View只负责UI显示和用户交互
测试规范检查项
- 单元测试覆盖核心业务逻辑
- Espresso测试覆盖主要用户流程
- 测试命名清晰表达预期行为
🔮 未来展望
随着Android开发的不断发展,建议关注以下趋势:
- Jetpack Compose - 新一代声明式UI框架
- Kotlin协程 - 替代RxJava的异步处理方案
- 模块化架构 - 提高大型项目的可维护性
- 测试驱动开发 - 更早发现和预防问题
保持对新技术的学习和适应,同时坚持良好的编码规范和架构设计原则,将帮助你在Android开发道路上走得更远。
立即行动:选择项目中最需要改进的一个模块,应用本文介绍的规范进行重构,体验规范化开发带来的好处!
下期预告:我们将深入探讨Android性能优化实战技巧,包括内存管理、网络优化、启动速度提升等核心话题。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



