Skip to content

Commit 4ea663d

Browse files
author
Clement Guyon
committed
perf: fix ChatListSortRooms redundant rebuilds and lifecycle leaks
1 parent 844b35b commit 4ea663d

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

lib/pages/chat_list/chat_list_sort_rooms.dart

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ class _ChatListSortRoomsState extends State<ChatListSortRooms> {
3030
Map<String, Event?> _lastEventByRoomId = {};
3131
List<Room> _sortCache = [];
3232
Map<String, StreamSubscription?> _roomSubscriptions = {};
33+
Future<List<Room>>? _sortFuture;
34+
35+
/// Monotonically increasing counter to invalidate stale sort futures.
36+
/// Each call to [_triggerSort] increments this value. When a sort future
37+
/// completes, it checks whether its generation matches [_sortGeneration].
38+
/// If not, the result is discarded (a newer sort has been triggered).
39+
int _sortGeneration = 0;
3340

3441
RoomSorter sortRoomsBy(Client client) => (a, b) {
3542
if (client.pinInvitedRooms &&
@@ -53,19 +60,34 @@ class _ChatListSortRoomsState extends State<ChatListSortRooms> {
5360
);
5461
};
5562

56-
Future<List<Room>> sortRooms() async {
63+
Future<List<Room>> _sortRooms(int generation) async {
5764
await Matrix.of(context).initSettingsCompleter.future;
5865
for (final room in widget.rooms) {
66+
// Bail out early if the widget was disposed or a newer sort was
67+
// triggered while we were awaiting.
68+
if (!mounted || generation != _sortGeneration) return _sortCache;
69+
5970
if (_lastEventByRoomId[room.id] != null) continue;
6071

6172
final event = await room.lastEventAvailableInPreview();
73+
74+
if (!mounted || generation != _sortGeneration) return _sortCache;
75+
6276
_lastEventByRoomId[room.id] = event;
6377
}
78+
79+
if (!mounted) return _sortCache;
80+
6481
widget.sortingRoomsNotifier.value = false;
6582
return List.from(widget.rooms)
6683
..sort(sortRoomsBy(Matrix.of(context).client));
6784
}
6885

86+
void _triggerSort() {
87+
_sortGeneration++;
88+
_sortFuture = _sortRooms(_sortGeneration);
89+
}
90+
6991
@override
7092
void initState() {
7193
super.initState();
@@ -82,6 +104,7 @@ class _ChatListSortRoomsState extends State<ChatListSortRooms> {
82104
),
83105
),
84106
);
107+
_triggerSort();
85108
}
86109

87110
@override
@@ -114,12 +137,24 @@ class _ChatListSortRoomsState extends State<ChatListSortRooms> {
114137
),
115138
),
116139
);
140+
_triggerSort();
141+
}
142+
143+
@override
144+
void dispose() {
145+
for (final subscription in _roomSubscriptions.values) {
146+
subscription?.cancel();
147+
}
148+
_roomSubscriptions.clear();
149+
// Invalidate any in-flight sort future so its callbacks become no-ops.
150+
_sortGeneration++;
151+
super.dispose();
117152
}
118153

119154
@override
120155
Widget build(BuildContext context) {
121156
return FutureBuilder(
122-
future: sortRooms(),
157+
future: _sortFuture,
123158
builder: (context, snapshot) {
124159
if (snapshot.data != null) {
125160
_sortCache = snapshot.data!;

lib/utils/matrix_sdk_extensions/hive_collections_database.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import 'dart:async';
2222
import 'dart:convert';
2323
import 'dart:math';
24-
import 'dart:typed_data';
2524

2625
import 'package:collection/collection.dart';
2726
import 'package:hive/hive.dart';

0 commit comments

Comments
 (0)