viewer: improved video controller disposing
This commit is contained in:
parent
1fd3d77bf9
commit
969187444b
2 changed files with 19 additions and 12 deletions
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/props.dart';
|
import 'package:aves/model/entry/extensions/props.dart';
|
||||||
|
@ -15,7 +16,7 @@ import 'package:leak_tracker/leak_tracker.dart';
|
||||||
class VideoConductor {
|
class VideoConductor {
|
||||||
final CollectionLens? _collection;
|
final CollectionLens? _collection;
|
||||||
final List<AvesVideoController> _controllers = [];
|
final List<AvesVideoController> _controllers = [];
|
||||||
final List<StreamSubscription> _subscriptions = [];
|
final Map<AvesVideoController, StreamSubscription> _subscriptions = {};
|
||||||
final PlaybackStateHandler _playbackStateHandler = DatabasePlaybackStateHandler();
|
final PlaybackStateHandler _playbackStateHandler = DatabasePlaybackStateHandler();
|
||||||
|
|
||||||
final ValueNotifier<AvesVideoController?> playingVideoControllerNotifier = ValueNotifier(null);
|
final ValueNotifier<AvesVideoController?> playingVideoControllerNotifier = ValueNotifier(null);
|
||||||
|
@ -36,9 +37,6 @@ class VideoConductor {
|
||||||
if (kFlutterMemoryAllocationsEnabled) {
|
if (kFlutterMemoryAllocationsEnabled) {
|
||||||
LeakTracking.dispatchObjectDisposed(object: this);
|
LeakTracking.dispatchObjectDisposed(object: this);
|
||||||
}
|
}
|
||||||
_subscriptions
|
|
||||||
..forEach((sub) => sub.cancel())
|
|
||||||
..clear();
|
|
||||||
await _disposeAll();
|
await _disposeAll();
|
||||||
playingVideoControllerNotifier.dispose();
|
playingVideoControllerNotifier.dispose();
|
||||||
_controllers.clear();
|
_controllers.clear();
|
||||||
|
@ -47,22 +45,24 @@ class VideoConductor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AvesVideoController getOrCreateController(AvesEntry entry, {int? maxControllerCount}) {
|
Future<AvesVideoController> getOrCreateController(AvesEntry entry, {int? maxControllerCount}) async {
|
||||||
var controller = getController(entry);
|
var controller = getController(entry);
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
_controllers.remove(controller);
|
_controllers.remove(controller);
|
||||||
} else {
|
} else {
|
||||||
|
maxControllerCount = max(_defaultMaxControllerCount, maxControllerCount ?? 0);
|
||||||
|
while (_controllers.length >= maxControllerCount) {
|
||||||
|
await _disposeController(_controllers.removeLast());
|
||||||
|
}
|
||||||
|
await deviceService.requestGarbageCollection();
|
||||||
controller = videoControllerFactory.buildController(
|
controller = videoControllerFactory.buildController(
|
||||||
entry,
|
entry,
|
||||||
playbackStateHandler: _playbackStateHandler,
|
playbackStateHandler: _playbackStateHandler,
|
||||||
settings: settings,
|
settings: settings,
|
||||||
);
|
);
|
||||||
_subscriptions.add(controller.statusStream.listen((event) => _onControllerStatusChanged(entry, controller!, event)));
|
_subscriptions[controller] = controller.statusStream.listen((event) => _onControllerStatusChanged(entry, controller!, event));
|
||||||
}
|
}
|
||||||
_controllers.insert(0, controller);
|
_controllers.insert(0, controller);
|
||||||
while (_controllers.length > (maxControllerCount ?? _defaultMaxControllerCount)) {
|
|
||||||
_controllers.removeLast().dispose();
|
|
||||||
}
|
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,9 +99,14 @@ class VideoConductor {
|
||||||
|
|
||||||
Future<void> _applyToAll(FutureOr Function(AvesVideoController controller) action) => Future.forEach<AvesVideoController>(_controllers, action);
|
Future<void> _applyToAll(FutureOr Function(AvesVideoController controller) action) => Future.forEach<AvesVideoController>(_controllers, action);
|
||||||
|
|
||||||
Future<void> _disposeAll() => _applyToAll((controller) => controller.dispose());
|
Future<void> _disposeAll() => _applyToAll(_disposeController);
|
||||||
|
|
||||||
Future<void> pauseAll() => _applyToAll((controller) => controller.pause());
|
Future<void> pauseAll() => _applyToAll((controller) => controller.pause());
|
||||||
|
|
||||||
Future<void> muteAll(bool muted) => _applyToAll((controller) => controller.mute(muted));
|
Future<void> muteAll(bool muted) => _applyToAll((controller) => controller.mute(muted));
|
||||||
|
|
||||||
|
Future<void> _disposeController(AvesVideoController controller) async {
|
||||||
|
await _subscriptions.remove(controller)?.cancel();
|
||||||
|
await controller.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,7 @@ mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _initVideoController(AvesEntry entry) async {
|
Future<void> _initVideoController(AvesEntry entry) async {
|
||||||
final controller = context.read<VideoConductor>().getOrCreateController(entry);
|
final controller = await context.read<VideoConductor>().getOrCreateController(entry);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
|
||||||
if (videoAutoPlayEnabled || entry.isAnimated) {
|
if (videoAutoPlayEnabled || entry.isAnimated) {
|
||||||
|
@ -157,7 +157,9 @@ mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> {
|
||||||
if (videoPageEntries.isNotEmpty) {
|
if (videoPageEntries.isNotEmpty) {
|
||||||
// init video controllers for all pages that could need it
|
// init video controllers for all pages that could need it
|
||||||
final videoConductor = context.read<VideoConductor>();
|
final videoConductor = context.read<VideoConductor>();
|
||||||
videoPageEntries.forEach((entry) => videoConductor.getOrCreateController(entry, maxControllerCount: videoPageEntries.length));
|
await Future.forEach(videoPageEntries, (entry) async {
|
||||||
|
await videoConductor.getOrCreateController(entry, maxControllerCount: videoPageEntries.length);
|
||||||
|
});
|
||||||
|
|
||||||
// auto play/pause when changing page
|
// auto play/pause when changing page
|
||||||
Future<void> _onPageChanged() async {
|
Future<void> _onPageChanged() async {
|
||||||
|
|
Loading…
Reference in a new issue