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
_DefaultTabControllerState should dispose all created TabContoller instances. #136608
_DefaultTabControllerState should dispose all created TabContoller instances. #136608
Conversation
cc @polina-c |
/// | ||
/// This instance of [TabController] must not be used anymore and has to be | ||
/// disposed since [AnimationController] was injected into the new | ||
/// [TabController]. |
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.
Is this true? May be it is up to invoker if the instance can be used or not?
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.
To be honest, usage of the TabController
after the removal of AnimationController
from it (after the call of _copyWith
) is impossible because we have several “bang operators” which will throw:
_animationController!.value = index.toDouble(); |
_animationController! |
_animationController!.value = _index.toDouble(); |
double get offset => _animationController!.value - _index.toDouble(); |
_animationController!.value = value + _index.toDouble(); |
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 method does not do anything with the original instance, that makes it unusable, so it should not have opinion about what to do with it.
I suggest:
- Move
_animationController = null;
out of this method to the invokers, because the methods name does not assume any updates like this. - Revert update do the comment.
How does it sound?
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.
@polina-c, thanks for the suggestions. According to what you suggested, here is the new code:
@override
void didUpdateWidget(DefaultTabController oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.length != widget.length) {
...
final TabController newController = _controller._copyWith...
_controller._animationController = null;
_controller.dispose();
_controller = newController;
}
if (oldWidget.animationDuration != widget.animationDuration) {
final TabController newController = _controller._copyWith...
_controller._animationController = null;
_controller.dispose();
_controller = newController;
}
}
What do you think?
Does explicit nulling of the private member look good to you?
length: widget.length, | ||
animationDuration: widget.animationDuration, | ||
index: newIndex, | ||
previousIndex: previousIndex, | ||
); | ||
_controller.dispose(); | ||
_controller = newController; | ||
} | ||
|
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.
How about making it more readable:
TabController newController = _controller;
if (oldWidget.length != widget.length) {
newController = newController._copyWith...
}
if (oldWidget.animationDuration != widget.animationDuration) {
newController = newController._copyWith...
}
if (newController != _controller) {
_controller.dispose();
_controller = newController;
_animationController = null;
}
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.
@polina-c, thanks a lot for your suggestion, it looks much cleaner. But if we do it in such a way, then we will lose the reference to the first new TabController
if the length
and animationDuration
are changed at the same time.
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.
Really? Both _copyWith
are invoked for newController
, not for _controller
. so, nothing is lost.
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.
Maybe I am missing something, but here is how I see the flow in case both length
and animationDuration
was updated:
// newController = TabController0
TabController newController = _controller;
if (oldWidget.length != widget.length) {
// newController = TabController1
newController = newController._copyWith...
}
if (oldWidget.animationDuration != widget.animationDuration) {
// newController = TabController2
newController = newController._copyWith...
}
if (newController != _controller) {
_controller._animationController = null;
// TabController0.dispose()
_controller.dispose();
// _controller = TabController2
_controller = newController;
// TabController1 is lost
}
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.
Oh, I see now.
You are right.
Thanks for explanation.
Then the only question is about _animationController = null;
:
- Why we need it? Old controller is not referenced and is disposed, so what's the point to null _animationController?
- If it is needed, (1) it does not seem
_copyWith
is right method to do it and (2) there should be comment that explains why it is needed.
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.
Thanks for the review.
Under the hood, _copyWith
transfers AnimationController
from one TabController
to another.
/// Creates a new [TabController] with `index`, `previousIndex`, `length`, and
/// `animationDuration` if they are non-null.
///
/// This method is used by [DefaultTabController].
///
/// When [DefaultTabController.length] is updated, this method is called to
/// create a new [TabController] without creating a new [AnimationController].
TabController _copyWith({
...
}) {
...
return TabController._(
...
animationController: _animationController,
....
);
}
In dispose
method of the TabController
we have disposal of the AnimationController
.
@override
void dispose() {
_animationController?.dispose();
_animationController = null;
super.dispose();
}
We can't hold the same AnimationController
in both TabController
s because it will cause double disposal in the future. So, to not dispose recently injected AnimationController
in the old TabController
, we need to null it. It will be disposed in the new TabController
in the future.
This explains why I added nulling of the _animationController
in the _copyWith
method and added this comment:
/// This instance of [TabController] must not be used anymore and has to be
/// disposed since [AnimationController] was injected into the new
/// [TabController].
What can you suggest to improve or change?
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.
Got it. Thanks.
Then _copyWith
is now doing way more than just copying.
How about renaming _copyWith
to _copyWithAndDispose
, and making it fully disposing the original instance?
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.
Great suggestion, thanks!
Pushed the new version.
@polina-c, thanks for help and review! |
flutter/flutter@c2bd2c1...0883cb2 2023-10-20 engine-flutter-autoroll@skia.org Roll Packages from 09c6b11 to be915be (6 revisions) (flutter/flutter#136964) 2023-10-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from de780872533c to 9b88ff83fd82 (4 revisions) (flutter/flutter#136959) 2023-10-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from 1e107c21328a to de780872533c (1 revision) (flutter/flutter#136952) 2023-10-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from fd33e7e75eac to 1e107c21328a (1 revision) (flutter/flutter#136949) 2023-10-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from 9dd59f7fcff9 to fd33e7e75eac (1 revision) (flutter/flutter#136942) 2023-10-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from cc3356c0e68f to 9dd59f7fcff9 (1 revision) (flutter/flutter#136935) 2023-10-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from 504a99d93f42 to cc3356c0e68f (2 revisions) (flutter/flutter#136934) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 503b84295462 to 504a99d93f42 (3 revisions) (flutter/flutter#136930) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 3b0469b0c718 to 503b84295462 (1 revision) (flutter/flutter#136928) 2023-10-19 katelovett@google.com Revert "[Velocity Tracker] Fix: Issue 97761: Flutter Scrolling does not match iOS; inadvertent scrolling when user lifts up finger" (flutter/flutter#136905) 2023-10-19 christopherfujino@gmail.com [flutter_tools] move build_preview_test from commands/permeable to integration shard (flutter/flutter#136912) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from b40042ebb95b to 3b0469b0c718 (2 revisions) (flutter/flutter#136922) 2023-10-19 andrewrkolos@gmail.com do not include entries from `--dart-define-from-file` files in the gradle config or environment during build (flutter/flutter#136865) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from bfd2ffb9a8bc to b40042ebb95b (2 revisions) (flutter/flutter#136915) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 9d49175618f5 to bfd2ffb9a8bc (2 revisions) (flutter/flutter#136910) 2023-10-19 36861262+QuncCccccc@users.noreply.github.com Allow users to customize search algorithm in `DropdownMenu` (flutter/flutter#136848) 2023-10-19 21270878+elliette@users.noreply.github.com Upgrade Flutter deps to pull in latest vm_service and dwds (flutter/flutter#136734) 2023-10-19 15619084+vashworth@users.noreply.github.com [Reland] Skip injecting Bonjour settings when port publication is disabled (flutter/flutter#136842) 2023-10-19 sokolovskyi.konstantin@gmail.com _DefaultTabControllerState should dispose all created TabContoller instances. (flutter/flutter#136608) 2023-10-19 gspencergoog@users.noreply.github.com Reland: "Add code for updating `focusedChild` when removing grandchildren from scope" (flutter/flutter#136899) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 418dce4feaf7 to 9d49175618f5 (1 revision) (flutter/flutter#136901) 2023-10-19 34871572+gmackall@users.noreply.github.com Unmark linux_android platform_channels_benchmarks as flaky (flutter/flutter#136838) 2023-10-19 engine-flutter-autoroll@skia.org Roll Packages from 14aa69e to 09c6b11 (4 revisions) (flutter/flutter#136896) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 28cb2508b8e0 to 418dce4feaf7 (2 revisions) (flutter/flutter#136895) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC rmistry@google.com,stuartmorgan@google.com,tarrinneal@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
…r#5192) flutter/flutter@c2bd2c1...0883cb2 2023-10-20 engine-flutter-autoroll@skia.org Roll Packages from 09c6b11 to be915be (6 revisions) (flutter/flutter#136964) 2023-10-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from de780872533c to 9b88ff83fd82 (4 revisions) (flutter/flutter#136959) 2023-10-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from 1e107c21328a to de780872533c (1 revision) (flutter/flutter#136952) 2023-10-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from fd33e7e75eac to 1e107c21328a (1 revision) (flutter/flutter#136949) 2023-10-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from 9dd59f7fcff9 to fd33e7e75eac (1 revision) (flutter/flutter#136942) 2023-10-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from cc3356c0e68f to 9dd59f7fcff9 (1 revision) (flutter/flutter#136935) 2023-10-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from 504a99d93f42 to cc3356c0e68f (2 revisions) (flutter/flutter#136934) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 503b84295462 to 504a99d93f42 (3 revisions) (flutter/flutter#136930) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 3b0469b0c718 to 503b84295462 (1 revision) (flutter/flutter#136928) 2023-10-19 katelovett@google.com Revert "[Velocity Tracker] Fix: Issue 97761: Flutter Scrolling does not match iOS; inadvertent scrolling when user lifts up finger" (flutter/flutter#136905) 2023-10-19 christopherfujino@gmail.com [flutter_tools] move build_preview_test from commands/permeable to integration shard (flutter/flutter#136912) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from b40042ebb95b to 3b0469b0c718 (2 revisions) (flutter/flutter#136922) 2023-10-19 andrewrkolos@gmail.com do not include entries from `--dart-define-from-file` files in the gradle config or environment during build (flutter/flutter#136865) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from bfd2ffb9a8bc to b40042ebb95b (2 revisions) (flutter/flutter#136915) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 9d49175618f5 to bfd2ffb9a8bc (2 revisions) (flutter/flutter#136910) 2023-10-19 36861262+QuncCccccc@users.noreply.github.com Allow users to customize search algorithm in `DropdownMenu` (flutter/flutter#136848) 2023-10-19 21270878+elliette@users.noreply.github.com Upgrade Flutter deps to pull in latest vm_service and dwds (flutter/flutter#136734) 2023-10-19 15619084+vashworth@users.noreply.github.com [Reland] Skip injecting Bonjour settings when port publication is disabled (flutter/flutter#136842) 2023-10-19 sokolovskyi.konstantin@gmail.com _DefaultTabControllerState should dispose all created TabContoller instances. (flutter/flutter#136608) 2023-10-19 gspencergoog@users.noreply.github.com Reland: "Add code for updating `focusedChild` when removing grandchildren from scope" (flutter/flutter#136899) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 418dce4feaf7 to 9d49175618f5 (1 revision) (flutter/flutter#136901) 2023-10-19 34871572+gmackall@users.noreply.github.com Unmark linux_android platform_channels_benchmarks as flaky (flutter/flutter#136838) 2023-10-19 engine-flutter-autoroll@skia.org Roll Packages from 14aa69e to 09c6b11 (4 revisions) (flutter/flutter#136896) 2023-10-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 28cb2508b8e0 to 418dce4feaf7 (2 revisions) (flutter/flutter#136895) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC rmistry@google.com,stuartmorgan@google.com,tarrinneal@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
…oller instances. (flutter#136608)" This reverts commit 9fa9fd3.
…oller instances. (flutter#136608)" This reverts commit 9fa9fd3.
…oller instances. (#136608)" (#144579) This reverts commit 9fa9fd3. Fixes #144087. Fixes #138588. This crash has been reported previously from a customer in google3 in #138588, but we weren't able to track it down. Thankfully, a repro was now provided in #144087 (comment) which traced the crash down to a change made in #136608. This PR reverts that change to fix that crash for now. I will post a new PR shortly that will add a test to cover the use case that caused the crash with #136608 to make sure we don't re-introduce the crash in the future.
Description
Tests
material/tabs_test.dart
to usetestWidgetsWithLeakTracking
.Pre-launch Checklist
///
).