Re-land fix for not disposed TabController (#146745)

Fixes https://github.com/flutter/flutter/issues/144910
This commit is contained in:
Polina Cherkasova 2024-04-22 13:28:50 -07:00 committed by GitHub
parent d261a908d4
commit 1d7c680e25
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 13 additions and 9 deletions

View File

@ -140,13 +140,15 @@ class TabController extends ChangeNotifier {
/// Creates a new [TabController] with `index`, `previousIndex`, `length`, and
/// `animationDuration` if they are non-null.
/// `animationDuration` if they are non-null, and disposes current instance.
///
/// 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({
/// Instead the [_animationController] is nulled in current instance and
/// passed to the new instance.
TabController _copyWithAndDispose({
required int? index,
required int? length,
required int? previousIndex,
@ -155,13 +157,16 @@ class TabController extends ChangeNotifier {
if (index != null) {
_animationController!.value = index.toDouble();
}
return TabController._(
final TabController result = TabController._(
index: index ?? _index,
length: length ?? this.length,
animationController: _animationController,
previousIndex: previousIndex ?? _previousIndex,
animationDuration: animationDuration ?? _animationDuration,
);
_animationController = null;
dispose();
return result;
}
/// An animation whose value represents the current position of the [TabBar]'s
@ -489,7 +494,7 @@ class _DefaultTabControllerState extends State<DefaultTabController> with Single
newIndex = math.max(0, widget.length - 1);
previousIndex = _controller.index;
}
_controller = _controller._copyWith(
_controller = _controller._copyWithAndDispose(
length: widget.length,
animationDuration: widget.animationDuration,
index: newIndex,
@ -498,7 +503,7 @@ class _DefaultTabControllerState extends State<DefaultTabController> with Single
}
if (oldWidget.animationDuration != widget.animationDuration) {
_controller = _controller._copyWith(
_controller = _controller._copyWithAndDispose(
length: widget.length,
animationDuration: widget.animationDuration,
index: _controller.index,

View File

@ -126,6 +126,9 @@ class _AnimatedState extends State<AnimatedWidget> {
}
void _handleChange() {
if (!mounted) {
return;
}
setState(() {
// The listenable's state is our build state, and it changed already.
});

View File

@ -7,7 +7,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import '../widgets/semantics_tester.dart';
import 'feedback_tester.dart';
@ -121,9 +120,6 @@ Widget buildLeftRightApp({required List<String> tabs, required String value, boo
}
void main() {
// TODO(polina-c): dispose TabController, https://github.com/flutter/flutter/issues/144910 [leaks-to-clean]
LeakTesting.settings = LeakTesting.settings.withIgnoredAll();
setUp(() {
debugResetSemanticsIdCounter();
});