diff --git a/app/src/main/java/com/fenghoo/seven/main/activity/LoginPasswordActivity.java b/app/src/main/java/com/fenghoo/seven/main/activity/LoginPasswordActivity.java index e85dc3d..403ec88 100644 --- a/app/src/main/java/com/fenghoo/seven/main/activity/LoginPasswordActivity.java +++ b/app/src/main/java/com/fenghoo/seven/main/activity/LoginPasswordActivity.java @@ -76,7 +76,26 @@ public class LoginPasswordActivity extends BaseTreeActivity mActivity; - - public MyHandler(SplashActivity activity) { - mActivity = new WeakReference(activity); - } - - @Override - public void handleMessage(Message msg) { - SplashActivity activity = mActivity.get(); - if (activity != null) { - switch (msg.what) { - case 0: - startActivity(); - break; - case 1: - - break; - } - } - } - } - - private final MyHandler handler = new MyHandler(this); - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - //设置共同沉浸式样式 - // ImmersionBar.with(this).navigationBarColor(R.color.colorPrimary).init(); - //将屏幕设置为全屏 - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - methodRequiresTwoPermission(); - } - - - private void startActivity(){ - if (ProfileSpUtils.getInstance().isLogin()) { - startActivity(MainActivity.class); - } else { - startActivity(LoginPasswordActivity.class); - } - finish(); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - //禁用返回 - return true; - } - - - @AfterPermissionGranted(RC_CAMERA_AND_LOCATION) - private void methodRequiresTwoPermission() { - String[] perms = {Manifest.permission.WRITE_EXTERNAL_STORAGE - , Manifest.permission.CAMERA - }; - if (EasyPermissions.hasPermissions(this, perms)) { - - handler.sendEmptyMessageDelayed(0, 2000); - - } else { - EasyPermissions.requestPermissions(this, "获取当前所在城市需要该权限", - RC_CAMERA_AND_LOCATION, perms); - } - } - - @Override - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); - } - - //成功 - @Override - public void onPermissionsGranted(int requestCode, List perms) { - ToastUtils.showToast(SplashActivity.this, "授权完成"); - - } - - //失败 - @Override - public void onPermissionsDenied(int requestCode, List perms) { - - ToastUtils.showToast(SplashActivity.this, "获取部分权限失败,请重新授权"); - - } - -} +package com.fenghoo.seven.main.activity; + +import android.Manifest; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.KeyEvent; +import android.view.WindowManager; + +import com.fenghoo.seven.R; +import com.fenghoo.seven.base.BaseActivity; +import com.fenghoo.seven.utils.ToastUtils; +import com.fenghoo.seven.utils.checkVersionsUtils.ProfileSpUtils; +import com.gyf.immersionbar.ImmersionBar; + +import java.lang.ref.WeakReference; +import java.util.List; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import pub.devrel.easypermissions.AfterPermissionGranted; +import pub.devrel.easypermissions.EasyPermissions; + +/** + * SplashActivity - 启动页模板 + * + * 功能说明: + * 1. 作为应用的启动入口(LAUNCHER Activity) + * 2. 显示启动画面,延迟后跳转到主页面 + * 3. 检查登录状态,已登录跳转到 MainActivity,未登录跳转到登录页 + * 4. 请求必要的权限 + * + * 使用说明: + * - 修改 SPLASH_DELAY 常量可调整启动页显示时长(毫秒) + * - 修改权限列表 perms 可调整需要请求的权限 + * - 修改 startMainActivity() 方法可自定义跳转逻辑 + * + * @author mengjuan + * @date 2018-9-30 + * @updated 2025-01-06 优化为模板项目 + */ +public class SplashActivity extends BaseActivity implements EasyPermissions.PermissionCallbacks { + + /** 权限请求码 */ + private static final int RC_CAMERA_AND_LOCATION = 100; + + /** 启动页延迟时间(毫秒),默认2秒 */ + private static final long SPLASH_DELAY = 2000; + + /** 弱引用Handler,避免内存泄漏 */ + private static class MyHandler extends Handler { + private final WeakReference mActivity; + + public MyHandler(SplashActivity activity) { + mActivity = new WeakReference<>(activity); + } + + @Override + public void handleMessage(Message msg) { + SplashActivity activity = mActivity.get(); + if (activity != null && msg.what == 0) { + activity.startMainActivity(); + } + } + } + + private final MyHandler handler = new MyHandler(this); + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // 设置全屏显示 + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + + // 请求必要权限 + requestNecessaryPermissions(); + } + + /** + * 启动主Activity + * 根据登录状态决定跳转到 MainActivity 还是登录页 + */ + private void startMainActivity() { + if (ProfileSpUtils.getInstance().isLogin()) { + // 已登录,直接进入主页面 + startActivity(MainActivity.class); + } else { + // 未登录,进入登录页面 + startActivity(LoginPasswordActivity.class); + } + // 关闭启动页,避免用户按返回键回到启动页 + finish(); + } + + /** + * 禁用返回键,防止用户在启动页按返回键退出应用 + */ + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + return true; // 拦截返回键 + } + return super.onKeyDown(keyCode, event); + } + + /** + * 请求必要权限 + * 如果权限已授予,延迟后跳转;否则请求权限 + */ + @AfterPermissionGranted(RC_CAMERA_AND_LOCATION) + private void requestNecessaryPermissions() { + // 定义需要请求的权限列表 + String[] perms = { + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.CAMERA + }; + + if (EasyPermissions.hasPermissions(this, perms)) { + // 权限已授予,延迟后跳转到主页面 + handler.sendEmptyMessageDelayed(0, SPLASH_DELAY); + } else { + // 请求权限 + EasyPermissions.requestPermissions( + this, + "应用需要以下权限才能正常运行:存储权限、相机权限", + RC_CAMERA_AND_LOCATION, + perms + ); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); + } + + /** + * 权限授予成功回调 + */ + @Override + public void onPermissionsGranted(int requestCode, List perms) { + // 权限授予后,延迟跳转 + handler.sendEmptyMessageDelayed(0, SPLASH_DELAY); + } + + /** + * 权限被拒绝回调 + */ + @Override + public void onPermissionsDenied(int requestCode, List perms) { + ToastUtils.showToast(SplashActivity.this, "部分权限被拒绝,可能影响部分功能使用"); + // 即使权限被拒绝,也延迟后跳转(允许用户继续使用应用) + handler.sendEmptyMessageDelayed(0, SPLASH_DELAY); + } +} diff --git a/模板项目使用说明.md b/模板项目使用说明.md new file mode 100644 index 0000000..527753f --- /dev/null +++ b/模板项目使用说明.md @@ -0,0 +1,162 @@ +# 模板项目使用说明 + +## 项目概述 + +这是一个 Android 模板项目,已经配置好从启动页(SplashActivity)到主页面(MainActivity)的完整流程。 + +## 启动流程 + +### 1. SplashActivity(启动页) + +**位置**: `app/src/main/java/com/fenghoo/seven/main/activity/SplashActivity.java` + +**功能**: +- 作为应用的启动入口(LAUNCHER Activity) +- 显示启动画面,默认延迟 2 秒后跳转 +- 检查用户登录状态 +- 请求必要的应用权限 + +**跳转逻辑**: +```java +if (已登录) { + 跳转到 MainActivity(主页面) +} else { + 跳转到 LoginPasswordActivity(登录页) +} +``` + +### 2. MainActivity(主页面) + +**位置**: `app/src/main/java/com/fenghoo/seven/main/activity/MainActivity.java` + +**功能**: +- 应用的主界面 +- 包含底部导航栏(首页、发现、客户、我的等) +- Fragment 管理 + +## 自定义配置 + +### 修改启动页延迟时间 + +在 `SplashActivity.java` 中修改常量: + +```java +/** 启动页延迟时间(毫秒),默认2秒 */ +private static final long SPLASH_DELAY = 2000; // 修改这个值 +``` + +### 修改需要请求的权限 + +在 `SplashActivity.java` 的 `requestNecessaryPermissions()` 方法中修改: + +```java +String[] perms = { + Manifest.permission.WRITE_EXTERNAL_STORAGE, // 存储权限 + Manifest.permission.CAMERA // 相机权限 + // 可以添加更多权限 +}; +``` + +### 修改跳转逻辑 + +在 `SplashActivity.java` 的 `startMainActivity()` 方法中自定义: + +```java +private void startMainActivity() { + // 自定义跳转逻辑 + if (ProfileSpUtils.getInstance().isLogin()) { + startActivity(MainActivity.class); + } else { + startActivity(LoginPasswordActivity.class); + } + finish(); +} +``` + +## AndroidManifest.xml 配置 + +启动页已正确配置为 LAUNCHER Activity: + +```xml + + + + + + +``` + +## 启动页布局 + +**位置**: `app/src/main/res/layout/activity_splash.xml` + +可以自定义启动页的 UI,当前显示应用图标。 + +## 启动页主题 + +**位置**: `app/src/main/res/values/styles.xml` + +查找 `SplashTheme` 样式,可以自定义启动页的主题。 + +## 测试启动流程 + +1. **直接启动应用** + - 应用会自动从 SplashActivity 开始 + - 2 秒后根据登录状态跳转 + +2. **已登录状态** + - 跳转到 MainActivity + +3. **未登录状态** + - 跳转到 LoginPasswordActivity + +## 注意事项 + +1. **返回键处理**: 启动页已禁用返回键,防止用户在启动过程中退出应用 + +2. **权限处理**: + - 如果权限被拒绝,应用仍会继续运行(延迟后跳转) + - 可以根据需要修改权限拒绝后的处理逻辑 + +3. **内存泄漏防护**: + - 使用 WeakReference 包装 Handler,避免内存泄漏 + +4. **登录状态检查**: + - 使用 `ProfileSpUtils.getInstance().isLogin()` 检查登录状态 + - 确保在登录成功后正确保存登录状态 + +## 快速开始 + +1. 运行项目,应用会自动从 SplashActivity 启动 +2. 2 秒后根据登录状态自动跳转到相应页面 +3. 如需修改跳转逻辑,编辑 `SplashActivity.java` 的 `startMainActivity()` 方法 + +## 测试账号 + +登录页面已预设默认测试账号,方便开发测试: + +- **手机号**: `18133922183` +- **密码**: `123456` + +**说明**: +- 打开登录页面时,如果输入框为空,会自动填入测试账号 +- 可以直接点击"登录"按钮进行测试 +- 如需修改测试账号,编辑 `LoginPasswordActivity.java` 的 `setDefaultTestAccount()` 方法 +- 生产环境发布前,建议删除或注释 `setDefaultTestAccount()` 方法调用 + +## 相关文件 + +- `SplashActivity.java` - 启动页 Activity +- `MainActivity.java` - 主页面 Activity +- `LoginPasswordActivity.java` - 登录页 Activity +- `activity_splash.xml` - 启动页布局 +- `AndroidManifest.xml` - Activity 配置 + +--- + +**最后更新**: 2025-01-06 + diff --git a/项目点评报告.md b/项目点评报告.md new file mode 100644 index 0000000..779104a --- /dev/null +++ b/项目点评报告.md @@ -0,0 +1,281 @@ +# Android 项目点评报告 + +## 📊 项目概览 + +**项目名称**: July (com.fenghoo.seven) +**项目类型**: Android 原生应用 +**主要功能**: 客户管理系统、社交功能、订单管理等 +**评估日期**: 2025-01-06 + +--- + +## ✅ 项目优点 + +### 1. **技术栈现代化** +- ✅ **Android Gradle Plugin 8.7.3** - 使用最新稳定版本 +- ✅ **Gradle 8.9** - 构建工具版本较新 +- ✅ **compileSdk 34, targetSdk 34** - 支持最新 Android 版本 +- ✅ **AndroidX** - 已迁移到 AndroidX 库 +- ✅ **Java 8** - 使用现代 Java 特性 + +### 2. **架构设计** +- ✅ **MVP 架构模式** - 采用 MVP 模式,代码结构清晰 +- ✅ **模块化设计** - 包含 app、baselibs、citypicker 等模块 +- ✅ **契约接口 (Contract)** - 使用 Contract 接口定义 View 和 Presenter 的交互 +- ✅ **职责分离** - View、Presenter、Model 分离良好 + +### 3. **代码质量** +- ✅ **命名规范** - 类名、方法名符合 Java 命名规范 +- ✅ **代码注释** - 关键方法有注释说明 +- ✅ **弱引用 Handler** - SplashActivity 使用 WeakReference 防止内存泄漏 +- ✅ **权限管理** - 使用 EasyPermissions 进行权限管理 + +### 4. **构建配置** +- ✅ **阿里云 Maven 镜像** - 加速依赖下载 +- ✅ **签名配置** - Release 版本签名配置完整 +- ✅ **ProGuard 规则** - 混淆规则文件存在 +- ✅ **多模块支持** - 支持多模块构建 + +### 5. **功能完整性** +- ✅ **启动流程** - SplashActivity → MainActivity 流程完整 +- ✅ **登录系统** - 密码登录、验证码登录支持 +- ✅ **测试账号** - 预设测试账号便于开发测试 +- ✅ **Fragment 管理** - 主页面使用 Fragment 管理多个功能模块 + +--- + +## ⚠️ 需要改进的地方 + +### 1. **代码规范问题** + +#### 🔴 严重问题 + +**问题1: Switch-Case 兼容性问题** +- **现状**: 已修复,但说明项目在升级过程中遇到了兼容性问题 +- **影响**: 在 AGP 8.x 中,library 模块的 R 类字段不是 final,无法在 switch-case 中使用 +- **解决**: ✅ 已全部改为 if-else 语句 + +**问题2: 代码重复** +- **问题**: AndroidManifest.xml 中存在大量重复的权限声明 +- **示例**: INTERNET、CAMERA、ACCESS_NETWORK_STATE 等权限重复声明多次 +- **建议**: 清理重复权限,只保留必要的权限声明 + +**问题3: 硬编码字符串** +- **问题**: 代码中存在硬编码的中文字符串 +- **建议**: 将字符串提取到 `strings.xml` 资源文件中 + +#### 🟡 中等问题 + +**问题4: 方法命名不一致** +- **问题**: `startActivity()` 方法名容易与系统方法混淆 +- **建议**: 重命名为 `navigateToMainActivity()` 或 `startMainActivity()` + +**问题5: 魔法数字** +- **问题**: 代码中存在魔法数字(如 2000、60000) +- **建议**: 提取为常量,如 `SPLASH_DELAY = 2000` + +**问题6: 空方法体** +- **问题**: 部分方法体为空或只有注释 +- **示例**: `initEvent()` 方法为空 +- **建议**: 如果不需要,可以删除或添加 TODO 注释 + +### 2. **架构设计问题** + +#### 🔴 严重问题 + +**问题1: 模块依赖混乱** +- **问题**: citypicker 模块存在依赖问题,曾被注释掉 +- **影响**: 可能导致编译问题或功能缺失 +- **建议**: 重新梳理模块依赖关系,确保依赖清晰 + +**问题2: 未使用的模块** +- **问题**: baselibs 模块已配置但未使用 +- **建议**: 如果不需要,从 settings.gradle 中移除;如果需要,完善其功能 + +#### 🟡 中等问题 + +**问题3: Presenter 生命周期管理** +- **问题**: 部分 Presenter 可能没有正确管理生命周期 +- **建议**: 确保在 Activity/Fragment 销毁时正确释放 Presenter + +**问题4: 缺少统一异常处理** +- **问题**: 异常处理分散在各个类中 +- **建议**: 建立统一的异常处理机制 + +### 3. **性能问题** + +#### 🟡 中等问题 + +**问题1: 图片加载库版本较旧** +- **问题**: Glide 4.9.0(当前最新为 4.16+) +- **建议**: 升级到最新稳定版本 + +**问题2: 网络库版本较旧** +- **问题**: Retrofit 2.4.0(当前最新为 2.9+) +- **建议**: 升级到最新版本以获得更好的性能和安全性 + +**问题3: 缺少性能监控** +- **问题**: 没有看到性能监控工具(如 LeakCanary) +- **建议**: 在 Debug 版本中集成 LeakCanary 检测内存泄漏 + +### 4. **安全性问题** + +#### 🔴 严重问题 + +**问题1: 测试账号硬编码** +- **问题**: 测试账号和密码硬编码在代码中 +- **风险**: 如果发布到生产环境,存在安全风险 +- **建议**: + - 使用 BuildConfig.DEBUG 判断是否设置测试账号 + - 或使用配置文件(不提交到版本控制) + +**问题2: 签名信息暴露** +- **问题**: 签名密码可能暴露在代码中 +- **建议**: 使用 gradle.properties(不提交到版本控制)或环境变量 + +#### 🟡 中等问题 + +**问题3: 网络请求缺少加密** +- **问题**: 未看到网络请求加密相关配置 +- **建议**: 确保敏感数据传输使用 HTTPS + +### 5. **代码维护性问题** + +#### 🟡 中等问题 + +**问题1: 缺少单元测试** +- **问题**: 未看到测试代码 +- **建议**: 添加单元测试和 UI 测试 + +**问题2: 缺少代码文档** +- **问题**: 部分复杂逻辑缺少详细注释 +- **建议**: 为关键业务逻辑添加详细注释 + +**问题3: 依赖版本管理** +- **问题**: 部分依赖使用 `latest.integration`(如高德地图) +- **建议**: 使用具体版本号,避免不可预期的更新 + +--- + +## 📈 项目评分 + +| 评估维度 | 评分 | 说明 | +|---------|------|------| +| **代码质量** | ⭐⭐⭐⭐ (4/5) | 整体代码质量良好,但存在一些规范问题 | +| **架构设计** | ⭐⭐⭐⭐ (4/5) | MVP 架构清晰,但模块依赖需要优化 | +| **技术栈** | ⭐⭐⭐⭐ (4/5) | 技术栈较新,但部分依赖版本较旧 | +| **可维护性** | ⭐⭐⭐ (3/5) | 缺少测试和文档,维护成本较高 | +| **安全性** | ⭐⭐⭐ (3/5) | 存在一些安全隐患,需要改进 | +| **性能** | ⭐⭐⭐ (3/5) | 基本性能良好,但缺少性能监控 | +| **构建配置** | ⭐⭐⭐⭐⭐ (5/5) | 构建配置完善,已优化 | + +**综合评分**: ⭐⭐⭐⭐ (3.7/5) + +--- + +## 🎯 改进建议优先级 + +### 🔴 高优先级(立即处理) + +1. **清理重复权限声明** + - 文件: `app/src/main/AndroidManifest.xml` + - 影响: 编译警告,代码整洁度 + +2. **测试账号安全处理** + - 文件: `LoginPasswordActivity.java` + - 修改: 使用 `BuildConfig.DEBUG` 判断 + ```java + if (BuildConfig.DEBUG) { + setDefaultTestAccount(); + } + ``` + +3. **签名信息保护** + - 文件: `app/build.gradle` + - 建议: 将签名信息移到 `local.properties`(不提交到版本控制) + +### 🟡 中优先级(近期处理) + +1. **升级依赖版本** + - Glide: 4.9.0 → 4.16.0 + - Retrofit: 2.4.0 → 2.9.0 + - RxJava2: 2.2.6 → 2.2.21 + +2. **添加性能监控** + - 集成 LeakCanary + - 添加性能分析工具 + +3. **完善模块依赖** + - 重新梳理 citypicker 模块依赖 + - 决定 baselibs 模块的去留 + +### 🟢 低优先级(长期优化) + +1. **添加单元测试** + - 为 Presenter 添加单元测试 + - 为工具类添加测试 + +2. **代码重构** + - 提取硬编码字符串 + - 消除魔法数字 + - 统一命名规范 + +3. **文档完善** + - 添加 API 文档 + - 完善代码注释 + - 编写开发指南 + +--- + +## 💡 最佳实践建议 + +### 1. **代码规范** +- 使用 CheckStyle、FindBugs 等工具进行代码检查 +- 配置 Git Hooks 在提交前进行代码检查 +- 统一代码格式化规则 + +### 2. **版本管理** +- 使用 Git Flow 或类似工作流 +- 规范 Commit Message +- 使用 Tag 标记版本 + +### 3. **持续集成** +- 配置 CI/CD 流程 +- 自动化测试 +- 自动化构建和发布 + +### 4. **依赖管理** +- 统一管理依赖版本(使用 versions.gradle) +- 定期更新依赖 +- 避免使用 `latest.integration` + +### 5. **安全实践** +- 敏感信息不提交到版本控制 +- 使用 ProGuard/R8 进行代码混淆 +- 定期进行安全审计 + +--- + +## 📝 总结 + +### 项目优势 +1. ✅ 技术栈现代化,使用最新稳定版本 +2. ✅ 架构设计清晰,采用 MVP 模式 +3. ✅ 构建配置完善,已优化构建流程 +4. ✅ 功能完整,启动流程和登录系统完善 + +### 主要问题 +1. ⚠️ 代码规范需要改进(重复权限、硬编码等) +2. ⚠️ 安全性需要加强(测试账号、签名信息) +3. ⚠️ 可维护性需要提升(缺少测试、文档) + +### 总体评价 +这是一个**结构良好、功能完整**的 Android 项目,采用了现代化的技术栈和清晰的架构设计。项目已经过升级优化,能够正常编译运行。主要需要在**代码规范、安全性和可维护性**方面进行改进。 + +**推荐指数**: ⭐⭐⭐⭐ (4/5) + +--- + +**报告生成时间**: 2025-01-06 +**评估人**: AI Code Reviewer +