perf(player): 续看点加载与进度写盘改为并行且复用同一请求
进播放页与首次准备播放会各要一次续看点,同一次请求跑两遍还串在首帧前; 现在并发请求复用同一 Future,并与上一条进度写盘并行等待,少一个网络往返的起播延迟。 剧场网格海报按布局宽度限制解码尺寸,半屏卡片不再按原图解码。
This commit is contained in:
1 parent
0f777b19f2
commit
63191b4692
3 files changed
+51
-12
No files matched your search
@@ -7,6 +7,7 @@ import '../../../core/data/models/drama.dart';
|
||||
import '../../../core/formatting/count_format.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../core/theme/app_dimens.dart';
|
||||
import '../../../core/widgets/remote_image.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
|
||||
const int _columns = 2;
|
||||
@@ -218,16 +219,28 @@ class _DiscoverCoverImage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final url = AppConfig.mediaUrl(path);
|
||||
if (url.isEmpty) return _placeholder();
|
||||
return Image.network(
|
||||
url,
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
loadingBuilder: (context, child, progress) {
|
||||
if (progress == null) return child;
|
||||
return _placeholder();
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
// 卡片只有半屏宽,按原图解码一张竖版海报就是数 MB,按布局宽度限一下。
|
||||
final decodeWidth = constraints.hasBoundedWidth
|
||||
? resolveImageDecodePixels(
|
||||
constraints.maxWidth,
|
||||
MediaQuery.devicePixelRatioOf(context),
|
||||
)
|
||||
: null;
|
||||
return Image.network(
|
||||
url,
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
cacheWidth: decodeWidth,
|
||||
loadingBuilder: (context, child, progress) {
|
||||
if (progress == null) return child;
|
||||
return _placeholder();
|
||||
},
|
||||
errorBuilder: (_, _, _) => _placeholder(),
|
||||
);
|
||||
},
|
||||
errorBuilder: (_, _, _) => _placeholder(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,9 @@ class PlayerLogic extends ChangeNotifier {
|
||||
ResumePoint? resumePoint;
|
||||
bool resumeLoaded = false;
|
||||
|
||||
/// 续看点加载中的请求:进页与首次准备播放会同时触发,复用同一次请求。
|
||||
Future<void>? _resumePointLoad;
|
||||
|
||||
/// 票据三态:加载中 / 失败(可重试)/ 被后端判定为不可播放
|
||||
bool ticketLoading = false;
|
||||
String? ticketError;
|
||||
@@ -512,7 +515,15 @@ class PlayerLogic extends ChangeNotifier {
|
||||
}
|
||||
|
||||
/// 服务端续看位置:进播放页时取一次,用于"定位到上次那一集的那一秒"。
|
||||
Future<void> loadResumePoint() async {
|
||||
Future<void> loadResumePoint() {
|
||||
final inFlight = _resumePointLoad;
|
||||
if (inFlight != null) return inFlight;
|
||||
return _resumePointLoad = _loadResumePoint().whenComplete(() {
|
||||
_resumePointLoad = null;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _loadResumePoint() async {
|
||||
final entry = queue.entryAt(initialIndex);
|
||||
final cached = positionCache.read(
|
||||
entry.episode.id,
|
||||
@@ -1281,9 +1292,12 @@ class PlayerLogic extends ChangeNotifier {
|
||||
await _waitUntilFrameReady(player.controller);
|
||||
return;
|
||||
}
|
||||
await pendingWrite;
|
||||
// 上一条进度写盘与续看点拉取互不依赖,并行等,少一个网络往返的首帧延迟。
|
||||
// 服务端每剧只记一条:只有"记录里的那一集"才定位,其它集从头播
|
||||
if (resumePoint == null) await loadResumePoint();
|
||||
await Future.wait([
|
||||
pendingWrite,
|
||||
if (!resumeLoaded) loadResumePoint(),
|
||||
]);
|
||||
if (resumePositionFor(episode.id) == null) {
|
||||
final dramaId = _dramaIdForEpisode(episode.id);
|
||||
final cached = dramaId == null
|
||||
|
||||
Reference in new issue
Block a user