diff --git a/frontend/mobile-app/lib/features/mining/presentation/pages/mining_page.dart b/frontend/mobile-app/lib/features/mining/presentation/pages/mining_page.dart index 2c0d8787..76158791 100644 --- a/frontend/mobile-app/lib/features/mining/presentation/pages/mining_page.dart +++ b/frontend/mobile-app/lib/features/mining/presentation/pages/mining_page.dart @@ -36,17 +36,40 @@ class _MiningPageState extends ConsumerState { @override void initState() { super.initState(); + // 先同步检查本地头像,再异步加载其他数据 + _checkLocalAvatarSync(); _loadUserData(); } + /// 同步检查本地头像文件(在 build 之前快速获取) + void _checkLocalAvatarSync() { + WidgetsBinding.instance.addPostFrameCallback((_) async { + final accountService = ref.read(accountServiceProvider); + final localPath = await accountService.getLocalAvatarPath(); + if (mounted && localPath != null && _localAvatarPath == null) { + setState(() { + _localAvatarPath = localPath; + }); + } + }); + } + /// 加载用户数据 Future _loadUserData() async { final accountService = ref.read(accountServiceProvider); - final serialNum = await accountService.getUserSerialNum(); - final avatarSvg = await accountService.getAvatarSvg(); - final avatarUrl = await accountService.getAvatarUrl(); - final localAvatarPath = await accountService.getLocalAvatarPath(); + // 并行加载所有数据 + final results = await Future.wait([ + accountService.getUserSerialNum(), + accountService.getAvatarSvg(), + accountService.getAvatarUrl(), + accountService.getLocalAvatarPath(), + ]); + + final serialNum = results[0] as int?; + final avatarSvg = results[1] as String?; + final avatarUrl = results[2] as String?; + final localAvatarPath = results[3] as String?; if (mounted) { setState(() { @@ -386,16 +409,22 @@ class _MiningPageState extends ConsumerState { // 1. 优先显示本地缓存的头像文件 if (_localAvatarPath != null && _localAvatarPath!.isNotEmpty) { final file = File(_localAvatarPath!); - return Image.file( - file, - width: 80, - height: 80, - fit: BoxFit.cover, - errorBuilder: (context, error, stackTrace) { - // 本地文件加载失败,尝试网络URL - return _buildNetworkOrSvgAvatar(); - }, - ); + // 同步检查文件是否存在 + if (file.existsSync()) { + return Image.file( + file, + width: 80, + height: 80, + fit: BoxFit.cover, + cacheWidth: 160, // 2x 分辨率缓存,提升性能 + cacheHeight: 160, + gaplessPlayback: true, // 防止图片切换时闪烁 + errorBuilder: (context, error, stackTrace) { + // 本地文件加载失败,尝试网络URL + return _buildNetworkOrSvgAvatar(); + }, + ); + } } // 2. 没有本地缓存,尝试网络URL或SVG diff --git a/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart b/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart index c45b84de..7d9b3169 100644 --- a/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart +++ b/frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart @@ -64,18 +64,43 @@ class _ProfilePageState extends ConsumerState { void initState() { super.initState(); _startCountdown(); + // 先同步检查本地头像,再异步加载其他数据 + _checkLocalAvatarSync(); _loadUserData(); } + /// 同步检查本地头像文件(在 build 之前快速获取) + void _checkLocalAvatarSync() { + // 使用 WidgetsBinding 确保在第一帧渲染前执行 + WidgetsBinding.instance.addPostFrameCallback((_) async { + final accountService = ref.read(accountServiceProvider); + final localPath = await accountService.getLocalAvatarPath(); + if (mounted && localPath != null && _localAvatarPath == null) { + setState(() { + _localAvatarPath = localPath; + }); + } + }); + } + /// 加载用户数据 Future _loadUserData() async { final accountService = ref.read(accountServiceProvider); - final username = await accountService.getUsername(); - final serialNum = await accountService.getUserSerialNum(); - final avatarSvg = await accountService.getAvatarSvg(); - final avatarUrl = await accountService.getAvatarUrl(); - final localAvatarPath = await accountService.getLocalAvatarPath(); + // 并行加载所有数据 + final results = await Future.wait([ + accountService.getUsername(), + accountService.getUserSerialNum(), + accountService.getAvatarSvg(), + accountService.getAvatarUrl(), + accountService.getLocalAvatarPath(), + ]); + + final username = results[0] as String?; + final serialNum = results[1] as int?; + final avatarSvg = results[2] as String?; + final avatarUrl = results[3] as String?; + final localAvatarPath = results[4] as String?; if (mounted) { setState(() { @@ -365,16 +390,22 @@ class _ProfilePageState extends ConsumerState { // 1. 优先显示本地缓存的头像文件 if (_localAvatarPath != null && _localAvatarPath!.isNotEmpty) { final file = File(_localAvatarPath!); - return Image.file( - file, - width: 80, - height: 80, - fit: BoxFit.cover, - errorBuilder: (context, error, stackTrace) { - // 本地文件加载失败,尝试网络URL - return _buildNetworkOrSvgAvatar(); - }, - ); + // 同步检查文件是否存在 + if (file.existsSync()) { + return Image.file( + file, + width: 80, + height: 80, + fit: BoxFit.cover, + cacheWidth: 160, // 2x 分辨率缓存,提升性能 + cacheHeight: 160, + gaplessPlayback: true, // 防止图片切换时闪烁 + errorBuilder: (context, error, stackTrace) { + // 本地文件加载失败,尝试网络URL + return _buildNetworkOrSvgAvatar(); + }, + ); + } } // 2. 没有本地缓存,尝试网络URL或SVG