File tree Expand file tree Collapse file tree 3 files changed +66
-0
lines changed
Expand file tree Collapse file tree 3 files changed +66
-0
lines changed Original file line number Diff line number Diff line change @@ -1153,6 +1153,7 @@ Future<T?> showDialog<T>({
11531153 assert (barrierDismissible != null );
11541154 assert (useSafeArea != null );
11551155 assert (useRootNavigator != null );
1156+ assert (_debugIsActive (context));
11561157 assert (debugCheckHasMaterialLocalizations (context));
11571158
11581159 final CapturedThemes themes = InheritedTheme .capture (
@@ -1176,6 +1177,23 @@ Future<T?> showDialog<T>({
11761177 ));
11771178}
11781179
1180+ bool _debugIsActive (BuildContext context) {
1181+ if (context is Element && ! context.debugIsActive) {
1182+ throw FlutterError .fromParts (< DiagnosticsNode > [
1183+ ErrorSummary ('This BuildContext is no longer valid.' ),
1184+ ErrorDescription (
1185+ 'The showDialog function context parameter is a BuildContext that is no longer valid.'
1186+ ),
1187+ ErrorHint (
1188+ 'This can commonly occur when the showDialog function is called after awaiting a Future. '
1189+ 'In this situation the BuildContext might refer to a widget that has already been disposed during the await. '
1190+ 'Consider using a parent context instead.' ,
1191+ ),
1192+ ]);
1193+ }
1194+ return true ;
1195+ }
1196+
11791197/// A dialog route with Material entrance and exit animations,
11801198/// modal barrier color, and modal barrier behavior (dialog is dismissible
11811199/// with a tap on the barrier).
Original file line number Diff line number Diff line change @@ -3264,6 +3264,19 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
32643264 return isDefunct;
32653265 }
32663266
3267+ /// Returns true if the Element is active.
3268+ ///
3269+ /// This getter always returns false in profile and release builds.
3270+ /// See the lifecycle documentation for [Element] for additional information.
3271+ bool get debugIsActive {
3272+ bool isActive = false ;
3273+ assert (() {
3274+ isActive = _lifecycleState == _ElementLifecycle .active;
3275+ return true ;
3276+ }());
3277+ return isActive;
3278+ }
3279+
32673280 /// The object that manages the lifecycle of this element.
32683281 @override
32693282 BuildOwner ? get owner => _owner;
Original file line number Diff line number Diff line change @@ -2122,6 +2122,41 @@ void main() {
21222122 expect (nestedObserver.dialogCount, 1 );
21232123 });
21242124
2125+ testWidgets ('showDialog throws a friendly user message when context is not active' , (WidgetTester tester) async {
2126+ // Regression test for https://github.com/flutter/flutter/issues/12467
2127+ await tester.pumpWidget (
2128+ const MaterialApp (
2129+ home: Center (child: Text ('Test' )),
2130+ ),
2131+ );
2132+ final BuildContext context = tester.element (find.text ('Test' ));
2133+
2134+ await tester.pumpWidget (
2135+ const MaterialApp (
2136+ home: Center (),
2137+ ),
2138+ );
2139+
2140+ Object ? error;
2141+ try {
2142+ showDialog <void >(
2143+ context: context,
2144+ builder: (BuildContext innerContext) {
2145+ return const AlertDialog (title: Text ('Title' ));
2146+ },
2147+ );
2148+ } catch (exception) {
2149+ error = exception;
2150+ }
2151+
2152+ expect (error, isNotNull);
2153+ expect (error, isFlutterError);
2154+ if (error is FlutterError ) {
2155+ final ErrorSummary summary = error.diagnostics.first as ErrorSummary ;
2156+ expect (summary.toString (), 'This BuildContext is no longer valid.' );
2157+ }
2158+ });
2159+
21252160 group ('showDialog avoids overlapping display features' , () {
21262161 testWidgets ('positioning with anchorPoint' , (WidgetTester tester) async {
21272162 await tester.pumpWidget (
You can’t perform that action at this time.
0 commit comments