memory leak tracking & fixes
This commit is contained in:
parent
506190f882
commit
e883be1787
22 changed files with 107 additions and 13 deletions
|
@ -19,6 +19,7 @@ class Query extends ChangeNotifier {
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_focusRequestNotifier.dispose();
|
_focusRequestNotifier.dispose();
|
||||||
|
_queryNotifier.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ class CollectionLens with ChangeNotifier {
|
||||||
bool listenToSource, groupBursts, fixedSort;
|
bool listenToSource, groupBursts, fixedSort;
|
||||||
List<AvesEntry>? fixedSelection;
|
List<AvesEntry>? fixedSelection;
|
||||||
|
|
||||||
|
final Set<AvesEntry> _syntheticEntries = {};
|
||||||
List<AvesEntry> _filteredSortedEntries = [];
|
List<AvesEntry> _filteredSortedEntries = [];
|
||||||
|
|
||||||
Map<SectionKey, List<AvesEntry>> sections = Map.unmodifiable({});
|
Map<SectionKey, List<AvesEntry>> sections = Map.unmodifiable({});
|
||||||
|
@ -101,6 +102,7 @@ class CollectionLens with ChangeNotifier {
|
||||||
favourites.removeListener(_onFavouritesChanged);
|
favourites.removeListener(_onFavouritesChanged);
|
||||||
filterChangeNotifier.dispose();
|
filterChangeNotifier.dispose();
|
||||||
sortSectionChangeNotifier.dispose();
|
sortSectionChangeNotifier.dispose();
|
||||||
|
_disposeSyntheticEntries();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,6 +120,11 @@ class CollectionLens with ChangeNotifier {
|
||||||
fixedSelection: fixedSelection ?? this.fixedSelection,
|
fixedSelection: fixedSelection ?? this.fixedSelection,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void _disposeSyntheticEntries() {
|
||||||
|
_syntheticEntries.forEach((v) => v.dispose());
|
||||||
|
_syntheticEntries.clear();
|
||||||
|
}
|
||||||
|
|
||||||
bool get isEmpty => _filteredSortedEntries.isEmpty;
|
bool get isEmpty => _filteredSortedEntries.isEmpty;
|
||||||
|
|
||||||
int get entryCount => _filteredSortedEntries.length;
|
int get entryCount => _filteredSortedEntries.length;
|
||||||
|
@ -182,6 +189,7 @@ class CollectionLens with ChangeNotifier {
|
||||||
|
|
||||||
void _applyFilters() {
|
void _applyFilters() {
|
||||||
final entries = fixedSelection ?? (filters.contains(TrashFilter.instance) ? source.trashedEntries : source.visibleEntries);
|
final entries = fixedSelection ?? (filters.contains(TrashFilter.instance) ? source.trashedEntries : source.visibleEntries);
|
||||||
|
_disposeSyntheticEntries();
|
||||||
_filteredSortedEntries = List.of(filters.isEmpty ? entries : entries.where((entry) => filters.every((filter) => filter.test(entry))));
|
_filteredSortedEntries = List.of(filters.isEmpty ? entries : entries.where((entry) => filters.every((filter) => filter.test(entry))));
|
||||||
|
|
||||||
if (groupBursts) {
|
if (groupBursts) {
|
||||||
|
@ -196,6 +204,7 @@ class CollectionLens with ChangeNotifier {
|
||||||
entries.sort(AvesEntrySort.compareByName);
|
entries.sort(AvesEntrySort.compareByName);
|
||||||
final mainEntry = entries.first;
|
final mainEntry = entries.first;
|
||||||
final burstEntry = mainEntry.copyWith(burstEntries: entries);
|
final burstEntry = mainEntry.copyWith(burstEntries: entries);
|
||||||
|
_syntheticEntries.add(burstEntry);
|
||||||
|
|
||||||
entries.skip(1).toList().forEach((subEntry) {
|
entries.skip(1).toList().forEach((subEntry) {
|
||||||
_filteredSortedEntries.remove(subEntry);
|
_filteredSortedEntries.remove(subEntry);
|
||||||
|
|
|
@ -41,6 +41,12 @@ class _QueryBarState extends State<QueryBar> {
|
||||||
_controller = TextEditingController(text: queryNotifier.value);
|
_controller = TextEditingController(text: queryNotifier.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final clearButton = IconButton(
|
final clearButton = IconButton(
|
||||||
|
|
|
@ -55,6 +55,12 @@ class _GridScaleGestureDetectorState<T> extends State<GridScaleGestureDetector<T
|
||||||
|
|
||||||
TileLayout get tileLayout => widget.tileLayout;
|
TileLayout get tileLayout => widget.tileLayout;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scaledSizeNotifier?.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final gestureSettings = MediaQuery.gestureSettingsOf(context);
|
final gestureSettings = MediaQuery.gestureSettingsOf(context);
|
||||||
|
@ -166,6 +172,7 @@ class _GridScaleGestureDetectorState<T> extends State<GridScaleGestureDetector<T
|
||||||
|
|
||||||
void _onScaleUpdate(ScaleUpdateDetails details) {
|
void _onScaleUpdate(ScaleUpdateDetails details) {
|
||||||
if (_scaledSizeNotifier == null) return;
|
if (_scaledSizeNotifier == null) return;
|
||||||
|
|
||||||
final s = details.scale;
|
final s = details.scale;
|
||||||
switch (tileLayout) {
|
switch (tileLayout) {
|
||||||
case TileLayout.mosaic:
|
case TileLayout.mosaic:
|
||||||
|
@ -181,6 +188,10 @@ class _GridScaleGestureDetectorState<T> extends State<GridScaleGestureDetector<T
|
||||||
void _onScaleEnd(ScaleEndDetails details) {
|
void _onScaleEnd(ScaleEndDetails details) {
|
||||||
if (_scaledSizeNotifier == null) return;
|
if (_scaledSizeNotifier == null) return;
|
||||||
|
|
||||||
|
final scaledSize = _scaledSizeNotifier!.value;
|
||||||
|
_scaledSizeNotifier!.dispose();
|
||||||
|
_scaledSizeNotifier = null;
|
||||||
|
|
||||||
final overlayEntry = _overlayEntry;
|
final overlayEntry = _overlayEntry;
|
||||||
_overlayEntry = null;
|
_overlayEntry = null;
|
||||||
if (overlayEntry != null) {
|
if (overlayEntry != null) {
|
||||||
|
@ -196,12 +207,11 @@ class _GridScaleGestureDetectorState<T> extends State<GridScaleGestureDetector<T
|
||||||
switch (tileLayout) {
|
switch (tileLayout) {
|
||||||
case TileLayout.mosaic:
|
case TileLayout.mosaic:
|
||||||
case TileLayout.grid:
|
case TileLayout.grid:
|
||||||
preferredExtent = _scaledSizeNotifier!.value.width;
|
preferredExtent = scaledSize.width;
|
||||||
case TileLayout.list:
|
case TileLayout.list:
|
||||||
preferredExtent = _scaledSizeNotifier!.value.height;
|
preferredExtent = scaledSize.height;
|
||||||
}
|
}
|
||||||
final newExtent = tileExtentController.setUserPreferredExtent(preferredExtent);
|
final newExtent = tileExtentController.setUserPreferredExtent(preferredExtent);
|
||||||
_scaledSizeNotifier = null;
|
|
||||||
if (newExtent == oldExtent) {
|
if (newExtent == oldExtent) {
|
||||||
_applyingScale = false;
|
_applyingScale = false;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -44,6 +44,7 @@ class _OverlayCoordinateFilterChipState extends State<OverlayCoordinateFilterChi
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_unregisterWidget(widget);
|
_unregisterWidget(widget);
|
||||||
|
_idleBoundsNotifier.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ import 'package:flutter/services.dart';
|
||||||
abstract class AvesSearchDelegate extends SearchDelegate {
|
abstract class AvesSearchDelegate extends SearchDelegate {
|
||||||
final String routeName;
|
final String routeName;
|
||||||
final bool canPop;
|
final bool canPop;
|
||||||
|
final TextEditingController queryTextController = TextEditingController();
|
||||||
|
final ValueNotifier<SearchBody?> currentBodyNotifier = ValueNotifier(null);
|
||||||
|
|
||||||
AvesSearchDelegate({
|
AvesSearchDelegate({
|
||||||
required this.routeName,
|
required this.routeName,
|
||||||
|
@ -31,6 +33,8 @@ abstract class AvesSearchDelegate extends SearchDelegate {
|
||||||
if (kFlutterMemoryAllocationsEnabled) {
|
if (kFlutterMemoryAllocationsEnabled) {
|
||||||
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
|
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
|
||||||
}
|
}
|
||||||
|
queryTextController.dispose();
|
||||||
|
currentBodyNotifier.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -113,8 +117,6 @@ abstract class AvesSearchDelegate extends SearchDelegate {
|
||||||
|
|
||||||
ScrollController? get suggestionsScrollController => null;
|
ScrollController? get suggestionsScrollController => null;
|
||||||
|
|
||||||
final TextEditingController queryTextController = TextEditingController();
|
|
||||||
|
|
||||||
final ProxyAnimation proxyAnimation = ProxyAnimation(kAlwaysDismissedAnimation);
|
final ProxyAnimation proxyAnimation = ProxyAnimation(kAlwaysDismissedAnimation);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -128,8 +130,6 @@ abstract class AvesSearchDelegate extends SearchDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final ValueNotifier<SearchBody?> currentBodyNotifier = ValueNotifier(null);
|
|
||||||
|
|
||||||
SearchBody? get currentBody => currentBodyNotifier.value;
|
SearchBody? get currentBody => currentBodyNotifier.value;
|
||||||
|
|
||||||
set currentBody(SearchBody? value) {
|
set currentBody(SearchBody? value) {
|
||||||
|
|
|
@ -26,6 +26,12 @@ class _DebugAndroidAppSectionState extends State<DebugAndroidAppSection> with Au
|
||||||
_loader = appService.getPackages();
|
_loader = appService.getPackages();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_queryNotifier.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
|
|
|
@ -23,6 +23,12 @@ class _DebugAndroidCodecSectionState extends State<DebugAndroidCodecSection> wit
|
||||||
_loader = AndroidDebugService.getCodecs();
|
_loader = AndroidDebugService.getCodecs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_queryNotifier.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
|
|
|
@ -71,9 +71,15 @@ class _DebugGeneralSectionState extends State<DebugGeneralSection> with Automati
|
||||||
debugPrint(' * report type=$reportType');
|
debugPrint(' * report type=$reportType');
|
||||||
groupBy(typedReports, (report) => report.trackedClass).forEach((trackedClass, classedReports) {
|
groupBy(typedReports, (report) => report.trackedClass).forEach((trackedClass, classedReports) {
|
||||||
debugPrint(' trackedClass=$trackedClass reports=${classedReports.length}');
|
debugPrint(' trackedClass=$trackedClass reports=${classedReports.length}');
|
||||||
// classedReports.forEach((report) {
|
classedReports.forEach((report) {
|
||||||
// debugPrint(' phase=${report.phase} retainingPath=${report.retainingPath} detailedPath=${report.detailedPath} context=${report.context}');
|
final phase = report.phase;
|
||||||
// });
|
final retainingPath = report.retainingPath;
|
||||||
|
final detailedPath = report.detailedPath;
|
||||||
|
final context = report.context;
|
||||||
|
if (phase != null || retainingPath != null || detailedPath != null || context != null) {
|
||||||
|
debugPrint(' phase=$phase retainingPath=$retainingPath detailedPath=$detailedPath context=$context');
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -34,6 +34,13 @@ class _EditEntryTitleDescriptionDialogState extends State<EditEntryTitleDescript
|
||||||
_descriptionTextController = TextEditingController(text: widget.initialDescription);
|
_descriptionTextController = TextEditingController(text: widget.initialDescription);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_titleTextController.dispose();
|
||||||
|
_descriptionTextController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MediaQueryDataProvider(
|
return MediaQueryDataProvider(
|
||||||
|
|
|
@ -52,7 +52,8 @@ class _RenameEntrySetPageState extends State<RenameEntrySetPage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_patternTextController.removeListener(_onUserPatternChanged);
|
_patternTextController.dispose();
|
||||||
|
_namingPatternNotifier.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ class _TagEditorPageState extends State<TagEditorPage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
_newTagTextController.dispose();
|
||||||
_newTagTextFocusNode.dispose();
|
_newTagTextFocusNode.dispose();
|
||||||
_expandedSectionNotifier.dispose();
|
_expandedSectionNotifier.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
|
|
@ -39,6 +39,7 @@ class _CreateAlbumDialogState extends State<CreateAlbumDialog> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
_nameController.dispose();
|
_nameController.dispose();
|
||||||
_nameFieldFocusNode.removeListener(_onFocus);
|
_nameFieldFocusNode.removeListener(_onFocus);
|
||||||
_nameFieldFocusNode.dispose();
|
_nameFieldFocusNode.dispose();
|
||||||
|
|
|
@ -28,6 +28,13 @@ class _PasswordDialogState extends State<PasswordDialog> {
|
||||||
_focusNode.requestFocus();
|
_focusNode.requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
_focusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AvesDialog(
|
return AvesDialog(
|
||||||
|
|
|
@ -22,6 +22,12 @@ class _PinDialogState extends State<PinDialog> {
|
||||||
bool _confirming = false;
|
bool _confirming = false;
|
||||||
String? _firstPin;
|
String? _firstPin;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final colorScheme = Theme.of(context).colorScheme;
|
final colorScheme = Theme.of(context).colorScheme;
|
||||||
|
|
|
@ -37,6 +37,12 @@ class _AppPickPageState extends State<AppPickPage> {
|
||||||
_loader = appService.getPackages();
|
_loader = appService.getPackages();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_queryNotifier.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final useTvLayout = settings.useTvLayout;
|
final useTvLayout = settings.useTvLayout;
|
||||||
|
|
|
@ -253,6 +253,12 @@ class _AddressRowState extends State<_AddressRow> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_addressLineNotifier.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final textScaleFactor = MediaQuery.textScaleFactorOf(context);
|
final textScaleFactor = MediaQuery.textScaleFactorOf(context);
|
||||||
|
|
|
@ -33,7 +33,7 @@ class HomeWidgetPainter {
|
||||||
ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba,
|
ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba,
|
||||||
}) async {
|
}) async {
|
||||||
final widgetSizePx = Size(widthPx.toDouble(), heightPx.toDouble());
|
final widgetSizePx = Size(widthPx.toDouble(), heightPx.toDouble());
|
||||||
late final ui.Image? entryImage;
|
final ui.Image? entryImage;
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
final extent = shape.extentPx(widgetSizePx, entry!) / devicePixelRatio;
|
final extent = shape.extentPx(widgetSizePx, entry!) / devicePixelRatio;
|
||||||
entryImage = await _getEntryImage(entry, extent);
|
entryImage = await _getEntryImage(entry, extent);
|
||||||
|
@ -48,6 +48,7 @@ class HomeWidgetPainter {
|
||||||
canvas.clipPath(path);
|
canvas.clipPath(path);
|
||||||
if (entryImage != null) {
|
if (entryImage != null) {
|
||||||
canvas.drawImage(entryImage, Offset(widgetSizePx.width - entryImage.width, widgetSizePx.height - entryImage.height) / 2, Paint());
|
canvas.drawImage(entryImage, Offset(widgetSizePx.width - entryImage.width, widgetSizePx.height - entryImage.height) / 2, Paint());
|
||||||
|
entryImage.dispose();
|
||||||
} else {
|
} else {
|
||||||
canvas.drawPaint(Paint()..shader = backgroundGradient.createShader(rect));
|
canvas.drawPaint(Paint()..shader = backgroundGradient.createShader(rect));
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,12 @@ class _MapAddressRowState extends State<MapAddressRow> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_addressLineNotifier.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final textScaleFactor = MediaQuery.textScaleFactorOf(context);
|
final textScaleFactor = MediaQuery.textScaleFactorOf(context);
|
||||||
|
|
|
@ -29,6 +29,12 @@ class _LocaleSelectionPageState extends State<LocaleSelectionPage> {
|
||||||
_selectedValue = settings.locale ?? LocaleTile.systemLocaleOption;
|
_selectedValue = settings.locale ?? LocaleTile.systemLocaleOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_queryNotifier.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final useTvLayout = settings.useTvLayout;
|
final useTvLayout = settings.useTvLayout;
|
||||||
|
|
|
@ -55,6 +55,7 @@ class _MetadataSectionSliverState extends State<MetadataSectionSliver> {
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_unregisterWidget(widget);
|
_unregisterWidget(widget);
|
||||||
|
_expandedDirectoryNotifier.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ class _EntryGoogleMapState<T> extends State<EntryGoogleMap<T>> with WidgetsBindi
|
||||||
_unregisterWidget(widget);
|
_unregisterWidget(widget);
|
||||||
_serviceMapController?.dispose();
|
_serviceMapController?.dispose();
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
_sizeNotifier.removeListener(_onSizeChange);
|
_sizeNotifier.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue