HeroController should dispatch creation and disposal events. (#137835)
This commit is contained in:
parent
0e7ed92988
commit
e8d9d9bfd5
@ -156,6 +156,12 @@ class _CupertinoTabViewState extends State<CupertinoTabView> {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_heroController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _updateObservers() {
|
||||
_navigatorObservers =
|
||||
List<NavigatorObserver>.of(widget.navigatorObservers)
|
||||
|
@ -784,7 +784,17 @@ class HeroController extends NavigatorObserver {
|
||||
///
|
||||
/// The [createRectTween] argument is optional. If null, the controller uses a
|
||||
/// linear [Tween<Rect>].
|
||||
HeroController({ this.createRectTween });
|
||||
HeroController({ this.createRectTween }) {
|
||||
// TODO(polina-c): stop duplicating code across disposables
|
||||
// https://github.com/flutter/flutter/issues/137435
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
MemoryAllocations.instance.dispatchObjectCreated(
|
||||
library: 'package:flutter/widgets.dart',
|
||||
className: '$HeroController',
|
||||
object: this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to create [RectTween]s that interpolate the position of heroes in flight.
|
||||
///
|
||||
@ -1043,6 +1053,12 @@ class HeroController extends NavigatorObserver {
|
||||
/// Releases resources.
|
||||
@mustCallSuper
|
||||
void dispose() {
|
||||
// TODO(polina-c): stop duplicating code across disposables
|
||||
// https://github.com/flutter/flutter/issues/137435
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
|
||||
}
|
||||
|
||||
for (final _HeroFlight flight in _flights.values) {
|
||||
flight.dispose();
|
||||
}
|
||||
|
@ -1060,6 +1060,7 @@ void main() {
|
||||
|
||||
testWidgetsWithLeakTracking('MaterialApp does create HeroController with the MaterialRectArcTween', (WidgetTester tester) async {
|
||||
final HeroController controller = MaterialApp.createMaterialHeroController();
|
||||
addTearDown(controller.dispose);
|
||||
final Tween<Rect?> tween = controller.createRectTween!(
|
||||
const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0),
|
||||
const Rect.fromLTRB(0.0, 0.0, 20.0, 20.0),
|
||||
|
@ -304,9 +304,12 @@ Future<void> main() async {
|
||||
testWidgetsWithLeakTracking('Heroes still animate after hero controller is swapped.', (WidgetTester tester) async {
|
||||
final GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>();
|
||||
final UniqueKey heroKey = UniqueKey();
|
||||
final HeroController controller1 = HeroController();
|
||||
addTearDown(controller1.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
HeroControllerScope(
|
||||
controller: HeroController(),
|
||||
controller: controller1,
|
||||
child: TestDependencies(
|
||||
child: Navigator(
|
||||
key: key,
|
||||
@ -352,15 +355,19 @@ Future<void> main() async {
|
||||
);
|
||||
},
|
||||
));
|
||||
|
||||
expect(find.byKey(heroKey), findsNothing);
|
||||
// Begins the navigation
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 30));
|
||||
expect(find.byKey(heroKey), isOnstage);
|
||||
final HeroController controller2 = HeroController();
|
||||
addTearDown(controller2.dispose);
|
||||
|
||||
// Pumps a new hero controller.
|
||||
await tester.pumpWidget(
|
||||
HeroControllerScope(
|
||||
controller: HeroController(),
|
||||
controller: controller2,
|
||||
child: TestDependencies(
|
||||
child: Navigator(
|
||||
key: key,
|
||||
@ -389,6 +396,7 @@ Future<void> main() async {
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// The original animation still flies.
|
||||
expect(find.byKey(heroKey), isOnstage);
|
||||
// Waits for the animation finishes.
|
||||
@ -3135,6 +3143,13 @@ Future<void> main() async {
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.getTopLeft(find.byType(Image)).dy, moreOrLessEquals(forwardRest, epsilon: 0.1));
|
||||
});
|
||||
|
||||
test('HeroController dispatches memory events', () async {
|
||||
await expectLater(
|
||||
await memoryEvents(() => HeroController().dispose(), HeroController),
|
||||
areCreateAndDispose,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
class TestDependencies extends StatelessWidget {
|
||||
|
@ -2367,6 +2367,8 @@ void main() {
|
||||
),
|
||||
);
|
||||
};
|
||||
addTearDown(spy.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
HeroControllerScope(
|
||||
controller: spy,
|
||||
@ -2437,6 +2439,8 @@ void main() {
|
||||
),
|
||||
);
|
||||
};
|
||||
addTearDown(spy.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
HeroControllerScope(
|
||||
controller: spy,
|
||||
@ -2506,6 +2510,7 @@ void main() {
|
||||
),
|
||||
);
|
||||
};
|
||||
addTearDown(spy1.dispose);
|
||||
final List<NavigatorObservation> observations2 = <NavigatorObservation>[];
|
||||
final HeroControllerSpy spy2 = HeroControllerSpy()
|
||||
..onPushed = (Route<dynamic>? route, Route<dynamic>? previousRoute) {
|
||||
@ -2517,6 +2522,8 @@ void main() {
|
||||
),
|
||||
);
|
||||
};
|
||||
addTearDown(spy2.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
TestDependencies(
|
||||
child: Stack(
|
||||
@ -2633,6 +2640,8 @@ void main() {
|
||||
|
||||
testWidgetsWithLeakTracking('hero controller subscribes to multiple navigators does throw', (WidgetTester tester) async {
|
||||
final HeroControllerSpy spy = HeroControllerSpy();
|
||||
addTearDown(spy.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
HeroControllerScope(
|
||||
controller: spy,
|
||||
@ -2671,6 +2680,8 @@ void main() {
|
||||
|
||||
testWidgetsWithLeakTracking('hero controller throws has correct error message', (WidgetTester tester) async {
|
||||
final HeroControllerSpy spy = HeroControllerSpy();
|
||||
addTearDown(spy.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
HeroControllerScope(
|
||||
controller: spy,
|
||||
|
Loading…
x
Reference in New Issue
Block a user