# flutter_start **Repository Path**: Cdiam/flutter_start ## Basic Information - **Project Name**: flutter_start - **Description**: flutter 学习实战示例仓库 - **Primary Language**: Dart - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2026-07-23 - **Last Updated**: 2026-07-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Flutter Demo 集合 Flutter 功能演示集合,包含 WebSocket 通信和 AI 聊天输入框两大模块。 ## 功能模块 ### 1. WebSocket Demo - ✅ 连接 / 断开 WebSocket(wss://echo.websocket.org 回显服务) - ✅ 发送 / 接收消息,聊天气泡 UI - ✅ 连接状态实时展示(连接中 / 已连接 / 未连接) - ✅ 自动心跳保活(Demo 中设为 5 秒方便观察,生产建议 30 秒) - ✅ 断线自动重连(指数退避:1s / 2s / 4s / 8s / 16s,最多 5 次) - ✅ 快捷发送按钮(普通文本 / JSON) - ✅ 发送 / 接收消息计数 ### 2. Chat Input Demo - ✅ 仿微信聊天输入框(文字 + 语音切换) - ✅ 长按录制语音,上滑取消发送 - ✅ 实时录音波形动画(audio_waveforms) - ✅ 底部展开面板:拍照 / 选图 / 上传文件 - ✅ 模拟 AI 回复 ## 快速启动 ```bash cd flutter_websocket_demo flutter pub get flutter run ``` ## 项目结构 ``` lib/ ├── main.dart # 入口 → 首页 ├── pages/ │ ├── home_page.dart # 首页(两个模块入口) │ ├── chat_page.dart # WebSocket Demo 页面 │ └── chat_input_demo_page.dart # Chat Input Demo 页面 ├── services/ │ └── websocket_service.dart # WebSocketService(核心封装) └── widgets/ ├── status_bar.dart # WebSocket 状态栏 ├── message_bubble.dart # 消息气泡 ├── chat_input_widget.dart # 仿微信输入框组件 └── file_button_panel.dart # 底部功能面板 assets/ └── image/chat/ # 输入框组件图标资源 ``` ## 依赖版本 | 包 | 版本 | 用途 | |---|---|---| | web_socket_channel | ^3.0.3 | WebSocket 通信 | | audio_waveforms | ^2.0.2 | 录音波形动画 | | image_picker | ^1.2.1 | 拍照 / 选图 | | file_picker | ^11.0.2 | 文件选择 | | permission_handler | ^12.0.3 | 运行时权限 | ## 平台权限 ### Android (`android/app/src/main/AndroidManifest.xml`) - `INTERNET` — 网络通信 - `RECORD_AUDIO` — 语音录制 - `CAMERA` — 拍照 - `READ_EXTERNAL_STORAGE` / `WRITE_EXTERNAL_STORAGE` — 文件选择 ### iOS (`ios/Runner/Info.plist`) - `NSMicrophoneUsageDescription` — 麦克风权限 - `NSCameraUsageDescription` — 相机权限 - `NSPhotoLibraryUsageDescription` — 相册权限 ## MVVM 设计模式 项目采用 MVVM 架构,以登录模块为例展示实现方式。 ### 架构结构 ``` ┌─────────────────┐ │ View │ ← LoginPage / _LoginPageView │ (纯展示层) │ • 无业务逻辑,只负责渲染 UI │ │ • 通过 Consumer 监听状态变化 │ │ • 通过 Provider 获取 ViewModel └────────┬────────┘ │ Consumer ▼ ┌─────────────────┐ │ ViewModel │ ← LoginViewModel │ (业务逻辑层) │ • 持有 UI 状态(isLoading, isLoggedIn, errorMessage) │ │ • 封装业务方法(login, logout, getUserInfo) │ │ • 通过 notifyListeners() 通知视图更新 └────────┬────────┘ │ 调用 ▼ ┌─────────────────┐ │ Model │ ← UserApi, TokenStorage │ (数据访问层) │ • 网络请求、本地存储、数据库操作 │ │ • 提供纯数据接口,不处理 UI 逻辑 └─────────────────┘ ``` ### 核心文件 | 文件 | 职责 | |------|------| | [login_page.dart](lib/pages/login_page.dart) | View:登录页面,使用 Consumer 监听状态 | | [login_view_model.dart](lib/view_models/login_view_model.dart) | ViewModel:登录业务逻辑和状态管理 | | [user_api.dart](lib/services/api/user_api.dart) | Model:用户相关接口调用 | | [token_storage.dart](lib/services/storage/token_storage.dart) | Model:Token 安全存储管理 | ### 面试常见问题 #### 1. MVVM 与 MVC 的区别? | 维度 | MVC | MVVM | |------|-----|------| | 耦合度 | Controller 直接操作 View,耦合高 | ViewModel 与 View 通过数据绑定,解耦 | | 测试性 | Controller 难以单元测试 | ViewModel 纯业务逻辑,易于测试 | | 职责划分 | Controller 既管业务又管视图 | ViewModel 专注业务,View 专注展示 | #### 2. ViewModel 的生命周期如何管理? - **ChangeNotifierProvider** 创建 ViewModel 实例,生命周期与 Widget 绑定 - Widget 销毁时自动调用 `dispose()`,释放资源 - 使用 `listen: false` 获取 ViewModel 实例,避免不必要的重建 #### 3. 为什么 View 要用 StatelessWidget? - MVVM 架构下,View 只负责展示,状态由 ViewModel 管理 - StatelessWidget 更轻量,性能更好 - 状态变化通过 Consumer 触发局部重建,而非整个页面重建 #### 4. notifyListeners() 的调用时机? - 状态变化后必须调用,否则 UI 不会更新 - 在异步操作的 `finally` 块中调用,确保无论成功失败都通知 - 避免在 `notifyListeners()` 后立即修改状态(会触发多次重建) #### 5. Consumer 的作用是什么? - **局部重建**:只重建 Consumer 内部的 Widget,而非整个页面 - **依赖注入**:自动获取 ViewModel 实例 - **性能优化**:通过 `child` 参数缓存不变的 Widget #### 6. Provider.of(context, listen: false) 的使用场景? - **只调用方法**,不关心返回值时使用 - 在事件回调中调用(如 `onPressed`) - 避免不必要的监听和重建 #### 7. ViewModel 中如何处理异步操作? ```dart Future login() async { _isLoading = true; notifyListeners(); try { await UserApi.login(username: _username, password: _password); _isLoggedIn = true; } catch (e) { _errorMessage = e.toString(); } finally { _isLoading = false; notifyListeners(); } } ``` - 异步操作前设置 `isLoading = true` - `try-catch-finally` 确保无论成功失败都更新状态 - `finally` 块中重置 `isLoading` 并通知 UI #### 8. 如何避免状态泄漏? - ViewModel 不要持有 BuildContext 引用 - 使用 `WidgetsBinding.instance.addPostFrameCallback` 延迟操作 - 在 `dispose()` 中取消订阅和定时器 #### 9. MVVM 的优势? - **关注点分离**:View、ViewModel、Model 职责清晰 - **可测试性**:ViewModel 纯逻辑,易于单元测试 - **代码复用**:同一 ViewModel 可对应多个 View - **维护性**:修改业务逻辑只需改 ViewModel #### 10. Flutter 中实现 MVVM 的方式? - **Provider**:官方推荐,轻量级,适合中小项目 - **Riverpod**:Provider 的改进版,更灵活,支持依赖注入 - **GetX**:集成路由、状态管理、依赖注入的一站式方案 - **Bloc**:基于 Stream,适合复杂状态管理场景