Browse Source

把两处网络请求移出启动与设备页的关键路径

会议模板不再挡启动与登录
_performParallelTasks 名字叫并行、实际完全串行(网络检查 → 版本检查 →
token 校验,后者内部又是 getLoginToken → getAppConfig → _initMeetingTemplate),
冷启动要串等 5 次网络往返,而 _initializeApp 要等这一整串跑完才允许导航。
其中 ②③ 之间的串行是刻意的(强更弹窗必须先出、把 splash 卡住,见 CLAUDE.md),
不能改回并行;但 _initMeetingTemplate 排在最后、**启动时没有任何地方要用它**
——模板只落 sqlite,由会议模板页 getMeetingTemplateList 消费。改成 unawaited,
模板照常拉取更新,启动不再等它。
登录流程里同一句挡在 Get.offAllNamed(Routes.home) 前面,一并改。

设备页先渲染再补登记
loadDevices 里 `await BesDeviceAuth.verifyConnected()` 串在 getdevices
前面,首次进入白名单没命中时会真的去打 user_binddevice(带 10s 超时),
整个页面干等两次网络往返——就是「点设备页半天没响应」。
- isLoading 改成只在本地无数据时才遮罩:onInit 里 _refreshFromUser() 本来
  就已经拿本地列表渲染过一次了,再盖一层纯属让用户对着转圈等。
- verifyConnected 挪到列表渲染之后、改成后台跑。它登记成功时会直接把设备
  塞进 User.instance.devices,回来 _refreshFromUser() 刷一次即可,
  不必再拉一遍 getdevices。

⚠️ 代价:首次连接的新耳机会晚一两秒才出现在列表里(以前是干等到它出现才
显示整个页面)。这是「页面立刻可见」的必然结果。

⚠️ 两处的实际收益都要在 release 包上量,debug 的 JIT 会把差异淹掉。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
main
Rodger-Wang 1 month ago
parent
commit
6a64c3d008
  1. 5
      apps/client/lib/modules/login/controllers/login_controller.dart
  2. 22
      apps/client/lib/modules/my_devices/controllers/my_devices_controller.dart
  3. 7
      apps/client/lib/modules/splash/controllers/splash_controller.dart

5
apps/client/lib/modules/login/controllers/login_controller.dart

@ -704,7 +704,10 @@ class LoginController extends GetxController {
// 获取app的配置信息
await getAppConfig();
await _initMeetingTemplate();
// 会议模板不挡登录:它只被会议模板页读取(落 sqlite),
// await 它等于让用户在登录按钮上多等一次网络往返才跳主页。
// 与 splash 的处理一致。
unawaited(_initMeetingTemplate());
// 登录成功 → 直接进入首页
Get.offAllNamed(Routes.home);
} else {

22
apps/client/lib/modules/my_devices/controllers/my_devices_controller.dart

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:get/get.dart';
import '/core/utils/logger.dart';
@ -35,13 +37,10 @@ class MyDevicesController extends GetxController {
/// 从服务端拉取最新的设备列表,并刷新 [User.instance.devices]。
Future<void> loadDevices() async {
if (!User.isLoggedIn()) return;
isLoading.value = true;
// 本地已有数据就不要遮罩:onInit 里 _refreshFromUser() 已经拿本地列表渲染过
// 一次了,再盖一层 loading 只会让用户对着转圈干等网络往返。
isLoading.value = User.instance.devices.isEmpty;
try {
// 补校当前连着的恒玄耳机(顺带完成绑定登记)。
// 「先连耳机、后登录」是很常见的顺序,那时候连接事件里的登记会因为
// 未登录而跳过;不在这里补一次,这台设备就要等下次重连才会出现在列表里。
// 放在拉取之前,这样这次刷新就能看到它。
await BesDeviceAuth.verifyConnected();
final response = await Api.getdevices();
if (response != null) {
final list = response['devices'] as List<dynamic>?;
@ -60,6 +59,17 @@ class MyDevicesController extends GetxController {
_refreshFromUser();
isLoading.value = false;
}
// 补校当前连着的恒玄耳机(顺带完成绑定登记)。
// 「先连耳机、后登录」是很常见的顺序,那时候连接事件里的登记会因为未登录
// 而跳过;不在这里补一次,这台设备就要等下次重连才会出现在列表里。
//
// ⚠️ 但**不能串在 getdevices 前面**:首次连接时白名单没命中,它会真的去打
// user_binddevice(带 10s 超时),整个页面就得干等这一趟——表现就是
// 「点设备页半天没响应」。放到列表渲染之后跑,页面立刻可见。
// 它登记成功时会直接把设备塞进 User.instance.devices,所以回来刷一次就够,
// 不必再拉一遍 getdevices。
unawaited(BesDeviceAuth.verifyConnected().then((_) => _refreshFromUser()));
}
/// 解绑设备:调接口成功后从本地列表移除;如果是当前连接的设备,断开并跳到扫描页。

7
apps/client/lib/modules/splash/controllers/splash_controller.dart

@ -218,7 +218,12 @@ class SplashController extends GetxController {
if (isLoggedIn) {
// 只有登录成功,才获取App配置
await getAppConfig();
await _initMeetingTemplate();
// ⚠️ 会议模板**不放在启动关键路径上**:它只被会议模板页读取
// (落 sqlite,由 SqfliteApi.getMeetingTemplateList 消费),
// 启动时没有任何地方要用。原来 await 它等于让每次冷启动的白屏
// 多背一次网络往返——而 _initializeApp 要等这一整串跑完才允许导航。
// 改成后台拉:模板照常更新,启动不再等它。
unawaited(_initMeetingTemplate());
} else {
await User.clearUserSession(); //
}

Loading…
Cancel
Save