File tree 3 files changed +66
-0
lines changed 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>({
1153
1153
assert (barrierDismissible != null );
1154
1154
assert (useSafeArea != null );
1155
1155
assert (useRootNavigator != null );
1156
+ assert (_debugIsActive (context));
1156
1157
assert (debugCheckHasMaterialLocalizations (context));
1157
1158
1158
1159
final CapturedThemes themes = InheritedTheme .capture (
@@ -1176,6 +1177,23 @@ Future<T?> showDialog<T>({
1176
1177
));
1177
1178
}
1178
1179
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
+
1179
1197
/// A dialog route with Material entrance and exit animations,
1180
1198
/// modal barrier color, and modal barrier behavior (dialog is dismissible
1181
1199
/// 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 {
3264
3264
return isDefunct;
3265
3265
}
3266
3266
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
+
3267
3280
/// The object that manages the lifecycle of this element.
3268
3281
@override
3269
3282
BuildOwner ? get owner => _owner;
Original file line number Diff line number Diff line change @@ -2122,6 +2122,41 @@ void main() {
2122
2122
expect (nestedObserver.dialogCount, 1 );
2123
2123
});
2124
2124
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
+
2125
2160
group ('showDialog avoids overlapping display features' , () {
2126
2161
testWidgets ('positioning with anchorPoint' , (WidgetTester tester) async {
2127
2162
await tester.pumpWidget (
You can’t perform that action at this time.
0 commit comments