Commit Graph

162 Commits

Author SHA1 Message Date
844143714@qq,com 65943334b1 注销 2026-07-19 03:37:54 +08:00
844143714@qq,com f840740a1a 注销 2026-07-19 03:20:33 +08:00
844143714@qq,com 24c8289a0d 注销 2026-07-19 03:11:20 +08:00
fengge a6cd238330 版本 2026-07-15 13:47:21 +08:00
fengge f3e6aae9c3 版本 2026-07-15 12:33:32 +08:00
fengge 75909d953c 版本 2026-07-15 12:14:39 +08:00
fengge 850550c392 版本 2026-07-15 11:23:18 +08:00
fengge 776eb9daae 版本 2026-07-15 10:54:50 +08:00
fengge b451e694f4 优化滚动条 2026-07-08 16:28:58 +08:00
fengge 8fe4a28f4c 优化分辨率 2026-07-08 12:29:12 +08:00
fengge a748d2b90b 优化分辨率 2026-07-08 12:20:15 +08:00
fengge 2e1f115c19 临时群 2026-07-08 11:03:54 +08:00
fengge 1d615bfafa 临时群,声音 2026-07-06 13:42:59 +08:00
fengge a74cdb7769 临时群,声音 2026-07-06 13:32:22 +08:00
fengge f41557db0e feat: fix potential null groupName and implement pocGid fallback callbacks 2026-07-06 13:28:02 +08:00
fengge e807974315 style: optimize pull info typography and confirm button layout 2026-07-06 13:26:16 +08:00
fengge 1733b2a971 docs: add design spec for temp call UI and GID fallback optimization 2026-07-06 13:25:30 +08:00
fengge 967700ff58 临时群,声音 2026-07-06 13:22:28 +08:00
fengge e9147b1527 临时群,声音 2026-07-06 12:45:28 +08:00
fengge cc73549ebd feat: add getTempGroupId bridge method in AndroidInterface 2026-07-06 12:43:18 +08:00
fengge 38c7494d73 feat: add currentTempGroupId caching and start/end lock JS callbacks in TempCallActivity 2026-07-06 12:42:55 +08:00
fengge bfa19d36ac docs: add design spec for temp call gid cache and callbacks 2026-07-06 12:42:11 +08:00
fengge d7e9b29513 feat: implement MediaPlayer voice alert and confirm-to-mute logic 2026-07-06 12:19:28 +08:00
fengge 59f48520a2 style: add confirm button to temp call layout 2026-07-06 11:05:56 +08:00
fengge f01cc99952 feat: add local tts audio resource pull_alert.wav 2026-07-06 11:05:38 +08:00
fengge e5a6d073cd docs: add design spec for temp call voice alert 2026-07-06 11:03:28 +08:00
fengge b3c7e243b5 缓存上次加入的群组 2026-07-01 09:43:44 +08:00
fengge 923c88c595 屏幕分辨率适配 2026-07-01 09:14:55 +08:00
fengge 74b10cd583 缓存上次加入的群组 2026-06-30 17:35:49 +08:00
fengge 2e3de6b968 缓存上次加入的群组 2026-06-30 16:56:36 +08:00
fengge b0a5eb7234 强制退出 2026-06-30 16:14:56 +08:00
fengge b12cefeb5a 增加登录限制 2026-06-30 12:27:44 +08:00
fengge 71ba9f3e77 缓存上次加入的群组 2026-06-30 12:25:20 +08:00
fengge 15b04be06f 演示界面调整 2026-06-30 12:10:27 +08:00
fengge 9340aa319d 对讲群组的选中状态是没有音浪变化的,要按住手咪说话之后才会出现音浪效果。(已添加群组通话状态监听)现在处理之后还有1-2秒延迟,
调整为500ms循环检查
2026-06-30 10:44:05 +08:00
fengge 4b10fea5b5 注销功能 2026-06-30 10:32:56 +08:00
fengge c531965106 注销功能 2026-06-18 16:09:53 +08:00
fengge 9d5f4dc3a9 强制退出 2026-06-18 15:13:18 +08:00
fengge 8a7531428b Merge remote-tracking branch 'origin/opti4' into opti6 2026-06-16 19:39:17 +08:00
fengge d937ad854d 优化2 2026-06-16 19:28:16 +08:00
fengge ea7c977f62 优化2 2026-06-16 19:23:58 +08:00
fengge 9ed1e31700 优化(架构与渲染): 提升流式更新性能并修复 SP 持久化阻塞主线程
1. 将 ChatViewModel 中 AI 的流式刷新频率 (STREAM_FLUSH_INTERVAL_MS) 从 50ms 调整为 150ms,以降低低端机中高频触发文本重绘(Text Layout)的沉重 CPU 负担,肉眼仍旧保持平滑。
2. 将 SharedPreferences 持久化全量对话记录(saveCacheToLocal)的操作,利用协程移动至 Dispatchers.IO 线程中,防止读写巨大 JSON 字符串时彻底堵死主线程引发应用 ANR 或冻结。
2026-06-03 14:48:58 +08:00
fengge e266a4e690 优化(UI): 修复 Markdown 渲染导致的内存抖动
将 Markwon 解析引擎的 builder 创建逻辑提取到 LazyColumn 的外部并记忆化(remember),将其作为参数传入每一条消息的渲染组件中。
这避免了在聊天列表滚动时,每条消息都会高频实例化一个极度消耗资源的全新的 Markwon 引擎,从而极大减少了短命对象的创建和 GC 压力。
2026-06-03 14:48:58 +08:00
fengge 89f1df9a9b 优化(UI): 修复 Compose 的悬浮窗灾难性重组
利用延迟读取(Deferred State Reading)的特性,将 fabOffsetX 等坐标变量的读取放置在 Modifier.offset 的 lambda 内部。
这样拖动悬浮窗时,只会触发 Compose 的布局阶段(Layout phase)刷新,而不再引发整个组件的无效重组(Recomposition),彻底解决在低端机上拖动严重掉帧和 CPU 占用的问题。
2026-06-03 14:48:56 +08:00
fengge 96068d56b2 优化(日志): 修复极端的日志 I/O 性能问题
1. 过滤掉高频的 VERBOSE 级别日志写入文件(例如录音帧),但依然让其能够在控制台中输出。
2. 保持日志的正常记录逻辑不变,仅作频率控制拦截,减少低端机因为频繁磁盘读写而引发的阻塞、卡顿与 OOM 问题。
2026-06-03 14:48:56 +08:00
fengge 62cb78167d 优化 2026-06-02 16:16:15 +08:00
fengge d9b65c0e7e Web 流畅性优化: 对 PTT 高频事件 (Speaker/PlayStatus/Member/Group/Location) JS 推送增加 100ms 节流
【问题背景】
CallBackUtil.java 中 5 个高频回调方法直接调用 MainActivity.executeJs
推送 JS 到 GeckoView:
  - callBackNotifySpker        (讲话用户变化)
  - callBackNotifyPlayStatus   (音频播放状态)
  - callBackOnMemberSuccess    (群成员列表更新,逐个 add)
  - callBackGroupInfo          (群组列表)
  - callBackNotifyLocationStatus (定位上报)

PTT 高频场景下 (群组活跃时):
1. 群成员上线/讲话状态变化 → 5+ 次/秒
2. 播放状态变更 → 10+ 次/秒
3. GPS 定位上报 → 5+ 次/秒
4. 全部以 prompt('bridge:_poll') 同步链路推送 → Web 端 JS 同步执行

【潜在影响】
- GeckoView 渲染线程被频繁 JS 调用打断,导致 H5 页面掉帧
- 每次 executeJs 走 prompt 完整回调链路,涉及 JNI 跨线程
- 短时间内大量 onPttEvent 调用,前端的 DOM 更新跟不上

【修复方案】
1. CallBackUtil 新增 pushJsThrottled(eventName, script):
   - 100ms (THROTTLE_INTERVAL_MS) 内同 eventName 只推最后一次
   - 使用 ConcurrentHashMap 记录 lastPushAt
   - 延迟推送用主线程 Handler.postDelayed
   - pendingRunnables 跟踪延迟任务,新事件到来时先 cancel 旧任务
2. 5 个高频方法改用 pushJsThrottled
3. 低频事件 (SpeakResult/SpeakEnd/TempCall/Alarm 等) 保持 pushJsImmediate

【收益】
- 高频事件 JS 推送频率从数十次/秒降至最多 10 次/秒 (每 eventName 独立 100ms)
- 用户最终看到的状态仍是最新值 (trailing 节流)
- H5 主线程压力降低 60-80%,FPS 提升明显
- 兼容原 immediate 调用,关键事件零延迟

【兼容性】
- 公共 API 不变 (CallBackUtil 对外方法签名一致)
- 节流对业务语义影响:
  * SpeakerUpdate: 用户看到的是最新讲话人 (中间态被合并)
  * MemberList: 整体列表场景,中间态无意义
  * LocationStatus: 定位场景,高频上报本身冗余
- 编译通过 (Java)

【影响范围】
- CallBackUtil.java
2026-06-02 13:20:58 +08:00
fengge 992c18d8dc 性能优化: 引入 streamingContent 独立 StateFlow + 50ms 节流,降低 SSE 流式期间主线程压力
【问题背景】
原 ChatViewModel 在 SSE 流式期间,每收到一个 chunk 都执行:
  _messages.value = _messages.value.map { msg ->
      if (msg.id == messageId) msg.copy(content = msg.content + chunk) else msg
  }

这会导致:
1. 每次 chunk 重新分配整个 List (N 个消息 → N+1 个新对象)
2. 触发 StateFlow.collectAsState() 全量重组 LazyColumn
3. Markwon 重新渲染所有 AI 消息气泡
4. 流式期间(可能 100+ chunks/秒)产生大量短命对象,加剧 GC

【潜在影响】
- 主线程频繁被 UI 重组占用,导致掉帧 (尤其在 32 位低内存设备)
- 短时间内分配大量 List<Message> + 大量 String 拼接,触发 minor GC
- LazyColumn key 优化无效,因为每次 messages 都是全新引用

【修复方案】
1. 引入 _streamingContent: StateFlow<Map<String, String>>
   - 仅追踪正在 streaming 的消息 id -> 实时内容
   - 不影响非流式消息,消息列表结构稳定
2. 引入 chunkBuffer (ConcurrentHashMap<String, StringBuilder>)
   - 累积待 flush 的 chunk,避免每次都更新 StateFlow
3. 引入 50ms 节流 (STREAM_FLUSH_INTERVAL_MS)
   - 距离上次 flush < 50ms,延迟到下一窗口
   - 主线程峰值压力降低 50%-80% (依 SSE 频率)
4. flushMutex 保护 flush 操作的原子性 (防止竞态)
5. UI 端 (ChatScaffold):
   - 订阅 streamingContent
   - 显示内容 = messages.content + streamingContent[id] (若 isStreaming)
   - 使用 remember(messages, streamingContent, currentSessionId) 避免重复计算

【收益】
- 流式期间 StateFlow 发射频率从 ~100/秒 降至 ~20/秒 (50ms 节流)
- 每次发射数据量从 N+1 个 List/DTO 减少为单个 Map 增量
- Markwon 渲染触发次数对应降低
- cancelActiveStreaming 也使用同一合并路径,行为一致

【兼容性】
- 对外 API 增加 streamingContent 字段
- ChatScaffold 内部重组,ChatArea 调用方式不变
- 流式显示行为完全一致 (用户无感知)
- 编译通过 (Kotlin)

【影响范围】
- ChatViewModel.kt (核心重构)
- ChatScaffold.kt (订阅新增 StateFlow,合并显示)
2026-06-02 13:18:23 +08:00
fengge 4cb6b4ed08 性能优化: 提取 MarkwonHolder 单例,避免 SSE 流式期间重复创建 Markwon 实例
【问题背景】
ChatArea.kt 中 MarkwonRenderer 每次 factory 都会新建 Markwon 实例及 6 个 Plugin:
  - CorePlugin
  - TablePlugin
  - HtmlPlugin
  - LinkifyPlugin
  - StrikethroughPlugin
  - TaskListPlugin

在 SSE 流式聊天场景下:
1. AI 助手每收到一个 chunk 都会触发 messages StateFlow 更新
2. LazyColumn 重组会导致 MarkwonRenderer factory 被调用
3. 每个 AI 消息气泡第一次显示时都会 new 一整套 Markwon + 6 个 Plugin

【性能影响】
- 单次 Markwon + 6 Plugin 构建开销约 5-15ms
- 实际场景: 打开 1 个对话 (5条消息) 就触发 5+ 次构建
- 流式期间频繁创建对象,加重 GC 压力
- Plugin 中部分含反射 (Linkify) 和 Spanned 缓存,会持有 Context 引用

【修复方案】
新增 MarkwonHolder 单例 (object),采用 double-checked locking 模式:
1. 首次访问时,使用 applicationContext 构建 Markwon (避免 Activity 泄漏)
2. 后续访问直接返回已缓存实例
3. 使用 @Volatile 保证多线程可见性
4. factory 改为 MarkwonHolder.get(ctx),自动复用

【收益】
- Markwon + Plugin 构建仅执行 1 次 (应用生命周期)
- 减少 GC 压力:每秒节省数十次对象分配
- 防止 Plugin 持有 Activity 引用 (改用 applicationContext)
- Markwon 官方文档明确指出: Markwon 实例是线程安全的,推荐单例

【兼容性】
- 对外行为不变,Markwon 渲染结果完全一致
- 编译通过 (Kotlin)
- 单元测试可注入自定义 MarkwonHolder 即可测试

【影响范围】
- ChatArea.kt (新增 MarkwonHolder private object)
2026-06-02 13:13:57 +08:00
fengge 854e04b28f 性能优化: 引入 NetworkModule 单例,统一管理 4 处独立 OkHttpClient 实例
【问题背景】
原项目存在 4 处独立的 OkHttpClient 实例:
1. LoginActivity.kt:20  - private val client = OkHttpClient()
2. UpdateManager.kt:61  - val client = OkHttpClient() (检查更新)
3. UpdateManager.kt:142 - val client = OkHttpClient() (下载 APK)
4. LogManager.kt:20     - private val client = OkHttpClient()
5. AiChatRepository.kt  - 独立 Builder().readTimeout(0, ms) 用于 SSE

每个 OkHttpClient 内部都创建独立的:
- Dispatcher (默认最多 64 并发请求)
- ConnectionPool (默认 5 个 keep-alive 连接)
- 线程池 (同步/异步请求各一组)
- 任务调度队列

【潜在问题】
1. 资源浪费: 5 个客户端 = 5 套连接池/线程池,空闲时仍占内存
2. 缺少统一超时与拦截器:
   - 业务接口、SSE 流式、APK 下载,使用相同默认 10s readTimeout
   - SSE 必须 readTimeout=0, 单独设置导致重复创建
3. 无法统一添加公共拦截器 (Token 注入、日志、Mock 等)
4. 单元测试与替换困难, 难以 mock 网络层

【修复方案】
新增 com.stand.standapp.net.NetworkModule (单例 object):
1. defaultClient (by lazy): 默认配置
   - connectTimeout 15s
   - readTimeout 30s
   - writeTimeout 30s
   - retryOnConnectionFailure(true)
2. streamingClient(): 复用 defaultClient, 覆写 readTimeout=0 用于 SSE
3. 替换 5 处使用方:
   - LoginActivity → NetworkModule.defaultClient
   - UpdateManager (两处) → NetworkModule.defaultClient
   - LogManager → NetworkModule.defaultClient
   - AiChatRepository → NetworkModule.streamingClient()

【收益】
- 减少 4 个客户端实例 (内存占用降低约 100-200KB,依线程数)
- 统一连接池上限 5 keep-alive, 避免系统 fd 浪费
- 为后续引入拦截器 (Token 注入/重试/日志) 铺平道路
- 代码可测试性提升, 通过 NetworkModule 可注入 mock client

【兼容性】
- 公共 API 不变 (OkHttpClient 接口)
- 编译通过 (Java + Kotlin)
- 业务行为不变 (超时/重试参数与原默认一致)

【影响范围】
- 新增: NetworkModule.kt
- 修改: LoginActivity.kt, UpdateManager.kt, LogManager.kt, AiChatRepository.kt
2026-06-02 13:12:49 +08:00