When the SpeedDial's child's action changes the state, it could lead to the SpeedDial no longer being displayed (I have created a simple example lower).
When this happens, an exception is thrown.
In speed_dial.dart, in the SpeedDial dispose function, backgroundOverlay!.remove is only called if _open is true.
But this is not the case in this example. In this scenario, backgroundOverlay!.dispose() is called yet the backgroundOverlay!.removed() was not.
@override
void dispose() {
if (widget.renderOverlay && backgroundOverlay != null) {
if (_open && backgroundOverlay!.mounted) backgroundOverlay!.remove();
backgroundOverlay!.dispose();
}
if (overlayEntry != null) {
if (_open && overlayEntry!.mounted) overlayEntry!.remove();
overlayEntry!.dispose();
}
_controller.dispose();
widget.openCloseDial?.removeListener(_onOpenCloseDial);
super.dispose();
}
Exception thrown:
════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown while finalizing the widget tree:
An OverlayEntry must first be removed from the Overlay before dispose is called.
'package:flutter/src/widgets/overlay.dart':
package:flutter/…/widgets/overlay.dart:1
Failed assertion: line 210 pos 12: '_overlay == null'
When the exception was thrown, this was the stack
#2 OverlayEntry.dispose
package:flutter/…/widgets/overlay.dart:210
#3 _SpeedDialState.dispose
package:flutter_speed_dial/src/speed_dial.dart:250
#4 StatefulElement.unmount
package:flutter/…/widgets/framework.dart:5105
#5 _InactiveElements._unmount
package:flutter/…/widgets/framework.dart:1917
#6 ListIterable.forEach (dart:_internal/iterable.dart:39:13)
#7 _InactiveElements._unmountAll
package:flutter/…/widgets/framework.dart:1926
#8 BuildOwner.lockState
package:flutter/…/widgets/framework.dart:2523
#9 BuildOwner.finalizeTree
package:flutter/…/widgets/framework.dart:2947
#10 WidgetsBinding.drawFrame
package:flutter/…/widgets/binding.dart:885
#11 RendererBinding._handlePersistentFrameCallback
package:flutter/…/rendering/binding.dart:378
#12 SchedulerBinding._invokeFrameCallback
package:flutter/…/scheduler/binding.dart:1175
#13 SchedulerBinding.handleDrawFrame
package:flutter/…/scheduler/binding.dart:1104
#14 SchedulerBinding._handleDrawFrame
package:flutter/…/scheduler/binding.dart:1015
#15 _invoke (dart:ui/hooks.dart:148:13)
#16 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:318:5)
#17 _drawFrame (dart:ui/hooks.dart:115:31)
(elided 2 frames from class _AssertionError)
════════════════════════════════════════════════════════════════════════════════
Reloaded 2 of 655 libraries in 770ms (compile: 17 ms, reload: 374 ms, reassemble: 342 ms).
When the SpeedDial's child's action changes the state, it could lead to the SpeedDial no longer being displayed (I have created a simple example lower).
When this happens, an exception is thrown. In speed_dial.dart, in the SpeedDial dispose function,
backgroundOverlay!.remove
is only called if_open
is true. But this is not the case in this example. In this scenario,backgroundOverlay!.dispose()
is called yet thebackgroundOverlay!.removed()
was not.Exception thrown:
Simple reproducible example: