New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add BuildContext.mounted #111619
Merged
Merged
Add BuildContext.mounted #111619
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2081,6 +2081,29 @@ typedef ElementVisitor = void Function(Element element); | |
/// | ||
/// {@youtube 560 315 https://www.youtube.com/watch?v=rIaaH87z1-g} | ||
/// | ||
/// Avoid storing instances of [BuildContext]s because they may become invalid | ||
/// if the widget they are associated with is unmounted from the widget tree. | ||
/// {@template flutter.widgets.BuildContext.asynchronous_gap} | ||
/// If a [BuildContext] is used across an asynchronous gap (i.e. after performing | ||
/// an asynchronous operation), consider checking [mounted] to determine whether | ||
/// the context is still valid before interacting with it: | ||
/// | ||
/// ```dart | ||
/// @override | ||
/// Widget build(BuildContext context) { | ||
/// return OutlinedButton( | ||
/// onPressed: () async { | ||
/// await Future<void>.delayed(const Duration(seconds: 1)); | ||
/// if (context.mounted) { | ||
/// Navigator.of(context).pop(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (here) |
||
/// } | ||
/// }, | ||
/// child: const Text('Delayed pop'), | ||
/// ); | ||
/// } | ||
/// ``` | ||
/// {@endtemplate} | ||
/// | ||
/// [BuildContext] objects are actually [Element] objects. The [BuildContext] | ||
/// interface is used to discourage direct manipulation of [Element] objects. | ||
abstract class BuildContext { | ||
|
@@ -2091,6 +2114,18 @@ abstract class BuildContext { | |
/// managing the rendering pipeline for this context. | ||
BuildOwner? get owner; | ||
|
||
/// Whether the [Widget] this context is associated with is currently | ||
/// mounted in the widget tree. | ||
/// | ||
/// Accessing the properties of the [BuildContext] or calling any methods on | ||
/// it is only valid while mounted is true. If mounted is false, assertions | ||
/// will trigger. | ||
/// | ||
/// Once unmounted, a given [BuildContext] will never become mounted again. | ||
/// | ||
/// {@macro flutter.widgets.BuildContext.asynchronous_gap} | ||
bool get mounted; | ||
|
||
/// Whether the [widget] is currently updating the widget or render tree. | ||
/// | ||
/// For [StatefulWidget]s and [StatelessWidget]s this flag is true while | ||
|
@@ -3271,6 +3306,9 @@ abstract class Element extends DiagnosticableTree implements BuildContext { | |
Widget get widget => _widget!; | ||
Widget? _widget; | ||
|
||
@override | ||
bool get mounted => _widget != null; | ||
|
||
/// Returns true if the Element is defunct. | ||
/// | ||
/// This getter always returns false in profile and release builds. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// Copyright 2014 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import 'package:flutter/widgets.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
|
||
void main() { | ||
testWidgets('StatefulWidget BuildContext.mounted', (WidgetTester tester) async { | ||
late BuildContext capturedContext; | ||
await tester.pumpWidget(TestStatefulWidget( | ||
onBuild: (BuildContext context) { | ||
capturedContext = context; | ||
} | ||
)); | ||
expect(capturedContext.mounted, isTrue); | ||
await tester.pumpWidget(Container()); | ||
expect(capturedContext.mounted, isFalse); | ||
}); | ||
|
||
testWidgets('StatelessWidget BuildContext.mounted', (WidgetTester tester) async { | ||
late BuildContext capturedContext; | ||
await tester.pumpWidget(TestStatelessWidget( | ||
onBuild: (BuildContext context) { | ||
capturedContext = context; | ||
} | ||
)); | ||
expect(capturedContext.mounted, isTrue); | ||
await tester.pumpWidget(Container()); | ||
expect(capturedContext.mounted, isFalse); | ||
}); | ||
} | ||
|
||
typedef BuildCallback = void Function(BuildContext); | ||
|
||
class TestStatelessWidget extends StatelessWidget { | ||
const TestStatelessWidget({super.key, required this.onBuild}); | ||
|
||
final BuildCallback onBuild; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
onBuild(context); | ||
return Container(); | ||
} | ||
} | ||
|
||
class TestStatefulWidget extends StatefulWidget { | ||
const TestStatefulWidget({super.key, required this.onBuild}); | ||
|
||
final BuildCallback onBuild; | ||
|
||
@override | ||
State<TestStatefulWidget> createState() => _TestStatefulWidgetState(); | ||
} | ||
|
||
class _TestStatefulWidgetState extends State<TestStatefulWidget> { | ||
@override | ||
Widget build(BuildContext context) { | ||
widget.onBuild(context); | ||
return Container(); | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is almost a functional example app. Would it make sense to make it into a full sample?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, it doesn't demonstrate anything visually though. In this case I think a full sample would actually distract from the point this is trying to make...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, makes sense. I mean it could show a dialog going away after a second, but I agree it's not all that visual.