fix(player): 收紧图片与快速切集资源占用
This commit is contained in:
1 parent
2fef7470e0
commit
80c962a95c
10 files changed
+281
-30
No files matched your search
@@ -75,7 +75,9 @@ void main() {
|
||||
expect(axis.cues, isEmpty);
|
||||
});
|
||||
|
||||
testWidgets('should_keep_only_two_decoded_sprites_in_lru', (tester) async {
|
||||
testWidgets('should_keep_one_sprite_and_reload_after_eviction', (
|
||||
tester,
|
||||
) async {
|
||||
final loader = _FakeSpriteLoader(vtt: _spriteVtt);
|
||||
final service = SpriteThumbnailAxisService(
|
||||
loader: loader,
|
||||
@@ -84,20 +86,37 @@ void main() {
|
||||
addTearDown(service.dispose);
|
||||
|
||||
await service.prepareAt('https://cdn.test/thumbnails.vtt', Duration.zero);
|
||||
expect(service.spriteCacheSize, 2);
|
||||
expect(
|
||||
service.spriteCacheKeys,
|
||||
containsAll(['sprite_001.jpg', 'sprite_002.jpg']),
|
||||
);
|
||||
|
||||
await service.prepareAt(
|
||||
'https://cdn.test/thumbnails.vtt',
|
||||
const Duration(milliseconds: 2500),
|
||||
);
|
||||
await service.prepareAt(
|
||||
'https://cdn.test/thumbnails.vtt',
|
||||
const Duration(milliseconds: 3500),
|
||||
);
|
||||
|
||||
expect(service.spriteCacheSize, 2);
|
||||
expect(service.spriteCacheKeys, contains('sprite_002.jpg'));
|
||||
expect(service.spriteCacheKeys, isNot(contains('sprite_001.jpg')));
|
||||
expect(service.spriteCacheSize, 1);
|
||||
expect(service.spriteCacheKeys, ['sprite_003.jpg']);
|
||||
expect(loader.images[0].debugDisposed, isTrue);
|
||||
expect(loader.images[1].debugDisposed, isTrue);
|
||||
expect(loader.images[2].debugDisposed, isFalse);
|
||||
expect(
|
||||
service.cachedFrameAt(
|
||||
'https://cdn.test/thumbnails.vtt',
|
||||
const Duration(milliseconds: 3500),
|
||||
),
|
||||
isNotNull,
|
||||
);
|
||||
|
||||
await service.prepareAt('https://cdn.test/thumbnails.vtt', Duration.zero);
|
||||
expect(service.spriteCacheSize, 1);
|
||||
expect(service.spriteCacheKeys, ['sprite_001.jpg']);
|
||||
expect(loader.images[2].debugDisposed, isTrue);
|
||||
expect(loader.images[3].debugDisposed, isFalse);
|
||||
expect(
|
||||
service.cachedFrameAt('https://cdn.test/thumbnails.vtt', Duration.zero),
|
||||
isNotNull,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('should_cache_vtt_and_retry_once_after_403', (tester) async {
|
||||
@@ -229,6 +248,7 @@ class _FakeSpriteLoader implements SpriteThumbnailAssetLoader {
|
||||
final List<Object>? vttResponses;
|
||||
int vttCalls = 0;
|
||||
final List<String> spriteCalls = [];
|
||||
final List<ui.Image> images = [];
|
||||
|
||||
@override
|
||||
Future<String?> loadVtt(Uri uri) async {
|
||||
@@ -244,6 +264,7 @@ class _FakeSpriteLoader implements SpriteThumbnailAssetLoader {
|
||||
Future<SpriteThumbnailDecodedImage?> loadSprite(Uri uri) async {
|
||||
spriteCalls.add(uri.pathSegments.last);
|
||||
final image = await _createImage(320, 180);
|
||||
images.add(image);
|
||||
return SpriteThumbnailDecodedImage(
|
||||
image: image,
|
||||
originalWidth: 320,
|
||||
|
||||
@@ -422,6 +422,42 @@ void main() {
|
||||
await _drain(logic);
|
||||
});
|
||||
|
||||
test('should_coalesce_rapid_page_selection_and_keep_pool_bounded', () async {
|
||||
final factory = _RecordingFactory();
|
||||
final playback = FakePlaybackRepository();
|
||||
final logic = _logic(FakeWatchHistory(), playback: playback);
|
||||
logic.attach(
|
||||
PlayerPage(
|
||||
drama: _drama('rapid', numbers: const [1, 2, 3, 4, 5, 6]),
|
||||
initialIndex: 0,
|
||||
),
|
||||
isMounted: () => true,
|
||||
);
|
||||
logic.start(factory: factory.create, coordinator: PlaybackCoordinator());
|
||||
await _drain(logic);
|
||||
|
||||
await Future.wait([
|
||||
for (var index = 1; index <= 5; index++)
|
||||
logic.requestEpisodeSelection(index),
|
||||
]);
|
||||
await _drain(logic);
|
||||
|
||||
expect(logic.session.currentIndex, 5);
|
||||
expect(playback.requests, containsAll(['rapid-1', 'rapid-2', 'rapid-6']));
|
||||
expect(playback.requests, isNot(contains('rapid-3')));
|
||||
expect(playback.requests, isNot(contains('rapid-4')));
|
||||
expect(playback.requests, isNot(contains('rapid-5')));
|
||||
expect(logic.session.livePlayerCount, lessThanOrEqualTo(3));
|
||||
expect(factory.live, lessThanOrEqualTo(3));
|
||||
|
||||
await logic.requestEpisodeSelection(0);
|
||||
await _drain(logic);
|
||||
expect(logic.session.currentIndex, 0);
|
||||
|
||||
logic.dispose();
|
||||
await _drain(logic);
|
||||
});
|
||||
|
||||
group('surface flags', () {
|
||||
test('should_set_immersive_when_picture_in_picture_callback_fires', () async {
|
||||
final factory = _RecordingFactory();
|
||||
|
||||
@@ -64,6 +64,38 @@ void main() {
|
||||
expect(loader.vttCalls, 0);
|
||||
});
|
||||
|
||||
testWidgets('should_decode_fullscreen_poster_at_screen_width', (
|
||||
tester,
|
||||
) async {
|
||||
final service = SpriteThumbnailAxisService(loader: _FakeSpriteLoader());
|
||||
addTearDown(service.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: MediaQuery(
|
||||
data: const MediaQueryData(devicePixelRatio: 3),
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 390,
|
||||
height: 844,
|
||||
child: PlayerOpeningFrame(
|
||||
posterUrl: 'https://cdn.test/poster.jpg',
|
||||
thumbnailsUrl: '',
|
||||
spriteSource: service,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final image = tester.widget<Image>(
|
||||
find.byKey(const Key('player-opening-poster')),
|
||||
);
|
||||
final provider = image.image as ResizeImage;
|
||||
expect(provider.width, 1170);
|
||||
});
|
||||
|
||||
testWidgets('should_return_no_opening_frame_when_thumbnails_is_empty', (
|
||||
tester,
|
||||
) async {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:fruitshorts/core/widgets/remote_image.dart';
|
||||
|
||||
void main() {
|
||||
test('should_bound_layout_pixels_for_small_and_large_extents', () {
|
||||
expect(resolveImageDecodePixels(12, 3), 96);
|
||||
expect(resolveImageDecodePixels(120, 3), 360);
|
||||
expect(resolveImageDecodePixels(4000, 3), 2048);
|
||||
});
|
||||
|
||||
testWidgets('should_decode_grid_cover_at_layout_width_times_dpr', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: MediaQuery(
|
||||
data: const MediaQueryData(devicePixelRatio: 3),
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 120,
|
||||
height: 160,
|
||||
child: RemoteImage('/files/grid-cover.jpg'),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final image = tester.widget<Image>(find.byType(Image));
|
||||
final provider = image.image as ResizeImage;
|
||||
expect(provider.width, 360);
|
||||
expect(provider.height, 480);
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user