fix: Add mounted checks and fix memory leaks across UI components

Address potential memory leaks and state-after-dispose issues:

- AppProvider: Add dispose method to clean up listeners and callbacks
- MapTab: Store and restore original location callback instead of nullifying
- MessagesTab: Use Timer instead of Future.delayed for highlight cleanup
- ConnectionDialog: Use named listener method for proper tab controller cleanup
- RoomLoginSheet: Add _isDisposed flag to handle async callback race conditions
- SettingsScreen: Clear location service callbacks in dispose
- Various screens: Add mounted checks before setState after async operations
  (contacts_tab, device_config, home_screen, map_management, packet_log,
   sar_template_management, sar_update_sheet, permission_request_dialog)
This commit is contained in:
Janez Troha
2025-12-04 19:34:48 +01:00
parent 3e2e4aa4d9
commit 96824e455e
15 changed files with 119 additions and 57 deletions

View File

@@ -22,6 +22,26 @@ class _ConnectionDialogState extends State<ConnectionDialog>
int _totalToScan = 0;
String? _connectingToServerUrl; // Track which server is being connected to
// Named listener method for proper cleanup
void _onTabChanged() {
if (_tabController.index == 1) {
// Switched to network tab
if (_networkScanner.hasCachedResults && _discoveredServers.isEmpty) {
// Load cached results
setState(() {
_discoveredServers.addAll(_networkScanner.cachedServers);
});
debugPrint(
'📦 [NetworkScanner] Loaded ${_discoveredServers.length} servers from cache',
);
} else if (!_networkScanner.isScanning &&
!_networkScanner.hasCachedResults) {
// No cache, start initial scan
_startNetworkScan();
}
}
}
@override
void initState() {
super.initState();
@@ -55,25 +75,8 @@ class _ConnectionDialogState extends State<ConnectionDialog>
}
};
// Listen to tab changes
_tabController.addListener(() {
if (_tabController.index == 1) {
// Switched to network tab
if (_networkScanner.hasCachedResults && _discoveredServers.isEmpty) {
// Load cached results
setState(() {
_discoveredServers.addAll(_networkScanner.cachedServers);
});
debugPrint(
'📦 [NetworkScanner] Loaded ${_discoveredServers.length} servers from cache',
);
} else if (!_networkScanner.isScanning &&
!_networkScanner.hasCachedResults) {
// No cache, start initial scan
_startNetworkScan();
}
}
});
// Listen to tab changes using named method for proper cleanup
_tabController.addListener(_onTabChanged);
}
@override
@@ -84,6 +87,8 @@ class _ConnectionDialogState extends State<ConnectionDialog>
);
connectionProvider.stopScan();
_networkScanner.stopScan();
// Remove listener before disposing to prevent memory leaks
_tabController.removeListener(_onTabChanged);
_tabController.dispose();
super.dispose();
}