Fix a memory leak in AutomaticKeepAlive (#124163)
Fix a memory leak in `AutomaticKeepAlive`
This commit is contained in:
@@ -144,7 +144,8 @@ class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> {
|
||||
}
|
||||
|
||||
VoidCallback _createCallback(Listenable handle) {
|
||||
return () {
|
||||
late final VoidCallback callback;
|
||||
return callback = () {
|
||||
assert(() {
|
||||
if (!mounted) {
|
||||
throw FlutterError(
|
||||
@@ -157,6 +158,7 @@ class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> {
|
||||
return true;
|
||||
}());
|
||||
_handles!.remove(handle);
|
||||
handle.removeListener(callback);
|
||||
if (_handles!.isEmpty) {
|
||||
if (SchedulerBinding.instance.schedulerPhase.index < SchedulerPhase.persistentCallbacks.index) {
|
||||
// Build/layout haven't started yet so let's just schedule this for
|
||||
|
||||
@@ -557,6 +557,26 @@ void main() {
|
||||
|
||||
expect(alternate.children.length, 1);
|
||||
});
|
||||
|
||||
testWidgets('Keep alive Listenable has its listener removed once called', (WidgetTester tester) async {
|
||||
final LeakCheckerHandle handle = LeakCheckerHandle();
|
||||
await tester.pumpWidget(Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: ListView.builder(
|
||||
itemCount: 1,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return const KeepAliveListenableLeakChecker(key: GlobalObjectKey<_KeepAliveListenableLeakCheckerState>(0));
|
||||
},
|
||||
),
|
||||
));
|
||||
final _KeepAliveListenableLeakCheckerState state = const GlobalObjectKey<_KeepAliveListenableLeakCheckerState>(0).currentState!;
|
||||
|
||||
expect(handle.hasListeners, false);
|
||||
state.dispatch(handle);
|
||||
expect(handle.hasListeners, true);
|
||||
handle.notifyListeners();
|
||||
expect(handle.hasListeners, false);
|
||||
});
|
||||
}
|
||||
|
||||
class _AlwaysKeepAlive extends StatefulWidget {
|
||||
@@ -633,3 +653,26 @@ class RenderSliverMultiBoxAdaptorAlt extends RenderSliver with
|
||||
@override
|
||||
void performLayout() { }
|
||||
}
|
||||
|
||||
class LeakCheckerHandle with ChangeNotifier {
|
||||
@override
|
||||
bool get hasListeners => super.hasListeners;
|
||||
}
|
||||
|
||||
class KeepAliveListenableLeakChecker extends StatefulWidget {
|
||||
const KeepAliveListenableLeakChecker({super.key});
|
||||
|
||||
@override
|
||||
State<KeepAliveListenableLeakChecker> createState() => _KeepAliveListenableLeakCheckerState();
|
||||
}
|
||||
|
||||
class _KeepAliveListenableLeakCheckerState extends State<KeepAliveListenableLeakChecker> {
|
||||
void dispatch(Listenable handle) {
|
||||
KeepAliveNotification(handle).dispatch(context);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Placeholder();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user