-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Introduce a migration guide for 3.10 new Zone error #8683
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
Merged
Merged
Changes from 2 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
1028101
Create zone-errors.md
Hixie a3c45f5
rewrap
Hixie 0f77159
Update src/release/breaking-changes/zone-errors.md
Hixie 428e8a6
Update zone-errors.md
Hixie 1fe7c8e
Update index.md
Hixie 7a710f5
Merge branch 'main' into Hixie-patch-1
Hixie 788ccf9
Fix breaking change index
parlough bce00f0
Clean up line lengths and sematic breaks
parlough File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,143 @@ | ||
| --- | ||
| title: "Zone mismatch" message | ||
| description: When Flutter's bindings are initialized in a different zone than the Zone used for `runApp`, a warning is printed to the console. | ||
| --- | ||
|
|
||
| ## Summary | ||
|
|
||
| Starting with Flutter 3.10, the framework detects mismatches when using Zones and reports them to the console in debug builds. | ||
|
|
||
| ## Background | ||
|
|
||
| Zones are a mechanism for managing callbacks in Dart. | ||
| While primarily useful for overriding `print` and `Timer` logic in tests, | ||
| and for catching errors in tests, | ||
| they are sometimes used for scoping global variables to certain parts of an application. | ||
|
|
||
| Flutter requires | ||
| (and has always required) | ||
| that all framework code be run in the same zone. | ||
| Notably, | ||
| this means that calls to `WidgetsFlutterBinding.ensureInitialized()` should be run in the same zone | ||
| as calls to `runApp()`. | ||
|
|
||
| Historically, Flutter has not detected such mismatches. | ||
| This sometimes leads to obscure and hard-to-debug issues. | ||
| For example, | ||
| a callback for keyboard input might be invoked | ||
| using a zone that does not have access to the `zoneValues` that it expects. | ||
| In our experience, | ||
| most if not all code that uses Zones | ||
| in a way that does not guarantee that all parts of the Flutter framework are working in the same Zone | ||
| has some latent bug. | ||
| Often these bugs appear unrelated to the use of Zones. | ||
|
|
||
| To help developers who have accidentally violated this invariant, | ||
| starting with Flutter 3.10, | ||
| a non-fatal warning is printed in debug builds when a mismatch is detected. | ||
| The warning looks like the following: | ||
|
|
||
| ``` | ||
| ════════ Exception caught by Flutter framework ════════════════════════════════════ | ||
| The following assertion was thrown during runApp: | ||
| Zone mismatch. | ||
|
|
||
| The Flutter bindings were initialized in a different zone than is now being used. | ||
| This will likely cause confusion and bugs as any zone-specific configuration will | ||
| inconsistently use the configuration of the original binding initialization zone or | ||
| this zone based on hard-to-predict factors such as which zone was active when a | ||
| particular callback was set. | ||
| It is important to use the same zone when calling `ensureInitialized` on the | ||
| binding as when calling `runApp` later. | ||
| To make this warning fatal, set BindingBase.debugZoneErrorsAreFatal to true before | ||
| the bindings are initialized (i.e. as the first statement in `void main() { }`). | ||
| [...] | ||
| ═══════════════════════════════════════════════════════════════════════════════════ | ||
| ``` | ||
|
|
||
| The warning can be made fatal by setting [`BindingBase.debugZoneErrorsAreFatal`] to true. | ||
| This flag may be changed to default to true in a future version of Flutter. | ||
parlough marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| ## Migration guide | ||
|
|
||
| The best way to silence this message is to remove use of Zones from within the application. | ||
| Zones can be very hard to debug, | ||
| because they are essentially global variables, | ||
| and break encapsulation. | ||
| Best practice is to avoid global variables and zones. | ||
|
|
||
| If removing zones is not an option | ||
| (for example because the application depends on a third-party library | ||
| that relies on zones for its configuration), | ||
| then the various calls into the Flutter framework | ||
| should be moved to all be in the same zone. | ||
| Typically, this means moving the call to `WidgetsFlutterBinding.ensureInitialized()` | ||
| to the same closure as the call to `runApp()`. | ||
|
|
||
| This can be awkward when the zone in which `runApp` is run | ||
| is being initialized with `zoneValues` obtained from a plugin | ||
| (which requires `WidgetsFlutterBinding.ensureInitialized()` to have been called). | ||
|
|
||
| One option in this kind of scenario is to place a mutable object in the `zoneValues`, | ||
| and update that object with the value once the value is available. | ||
|
|
||
| ```dart | ||
| import 'dart:async'; | ||
| import 'package:flutter/material.dart'; | ||
|
|
||
| class Mutable<T> { | ||
| Mutable(this.value); | ||
| T value; | ||
| } | ||
|
|
||
| void main() { | ||
| var myValue = Mutable<double>(0.0); | ||
| Zone.current.fork( | ||
| zoneValues: { | ||
| 'myKey': myValue, | ||
| } | ||
| ).run(() { | ||
| WidgetsFlutterBinding.ensureInitialized(); | ||
| var newValue = ...; // obtain value from plugin | ||
| myValue.value = newValue; // update value in Zone | ||
| runApp(...); | ||
| }); | ||
| } | ||
| ``` | ||
|
|
||
| In code that needs to use `myKey`, it can be obtained indirectly using `Zone.current['myKey'].value`. | ||
|
|
||
| When such a solution does not work | ||
| because a third-party dependency requires the use of a specific type for a specific `zoneValues` key, | ||
| all calls into the dependency can be wrapped in `Zone` calls that provide suitable values. | ||
|
|
||
| It is strongly recommended that packages that use zones in this way | ||
| migrate to more maintainable solutions. | ||
|
|
||
|
|
||
| ## Timeline | ||
|
|
||
| Landed in version: 3.9.0-9.0.pre<br> | ||
| In stable release: 3.10.0 | ||
|
|
||
| ## References | ||
|
|
||
| API documentation: | ||
|
|
||
| * [`Zone`][] | ||
| * [`BindingBase.debugZoneErrorsAreFatal`][] | ||
|
|
||
| Relevant issues: | ||
|
|
||
| * [Issue 94123][]: Flutter framework does not warn when ensureInitialized is called in a different zone than runApp | ||
|
|
||
| Relevant PRs: | ||
|
|
||
| * [PR 122836][https://github.com/flutter/flutter/pull/122836]: Assert that runApp is called in the same zone as binding.ensureInitialized | ||
parlough marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| https://github.com/flutter/flutter/issues/ | ||
parlough marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| [`Zone`]: {{site.api}}/flutter/dart-async/Zone-class.html | ||
| [`BindingBase.debugZoneErrorsAreFatal`]: {{site.api}}/flutter/foundation/BindingBase/debugZoneErrorsAreFatal.html | ||
| [Issue 94123]: {{site.repo.flutter}}/issues/94123 | ||
| [PR 122836]: {{site.repo.flutter}}/pull/122836 | ||
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.
Uh oh!
There was an error while loading. Please reload this page.