-
Notifications
You must be signed in to change notification settings - Fork 29.8k
Description
Steps to Reproduce
Given two similar MaterialApp, one using go_router and one who doesn't, the one using go_router is unable to restore the screen state when the app is restarted.
The best way to see this problem is by running the included code sample.
Their implementation is very similar:
MaterialApp.router(
restorationScopeId: 'app',
routerConfig: GoRouter(
restorationScopeId: 'router',
routes: [
GoRoute(
path: '/',
builder: (context, state) => const ScrollScreen(),
),
],
),
);and:
MaterialApp(
restorationScopeId: 'app',
home: ScrollScreen(),
);The one using GoRouter is unable to restore the state of the ScrollScreen when the app is restarted.
You can see this behavior with the attached widget tests in the "code" section.
I've looked for similar reported issues, but I couldn't find one that explains this exact problem:
- The example in https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/others/state_restoration.dart shows how to do state restoration for
GoRouter, which does not restore the state of the Pages, only the state of theGoRouter(e.g. the location) - [go_router] Preserve the state of routes #99124 is similar, but it refers to the restoration of pages while the app is still in use, e.g. navigating from Page1 to Page2 and keeping the state of Page1. This is a similar problem, however is not the same use-case, so I don't think this is a duplicated of that issue.
- This is a problem that I am facing while trying to migrate the sample app "veggieseasons" to use
go_router, at first I have thought this was a problem withShellRoutebut I have reduced the problem to a minimal example that doesn't useShellRoute. Link to the WIP PR: Migrateveggieseasonstogo_routersamples#1544
Expected results:
Both cases should work the same way. The screen state should be restored after restart just like when using a MaterialApp without GoRouter
Actual results:
In this case, the state of the screen when using GoRouter is not restored, and this can be seen by using the included widget tests.
Code sample
Add go_router to your project, then paste the following three classes into your main.dart.
Also, copy the two widget tests into your widget_test.dart to run them.
First class is the AppGoRoute, which is a simple MaterialApp that uses GoRouter.
class AppGoRoute extends StatelessWidget {
const AppGoRoute({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp.router(
restorationScopeId: 'app',
title: 'Flutter Demo',
routerConfig: GoRouter(
restorationScopeId: 'router',
routes: [
GoRoute(
path: '/',
builder: (context, state) => const ScrollScreen(),
),
],
),
);
}
}The second class is AppSimple, which is a simple MaterialApp that doesn't use GoRouter.
class AppSimple extends StatelessWidget {
const AppSimple({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return const MaterialApp(
restorationScopeId: 'app',
title: 'Flutter Demo',
home: ScrollScreen(),
);
}
}ScrollScreen is a simple Scaffold with a ListView of a 1000 items.
class ScrollScreen extends StatelessWidget {
const ScrollScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
restorationId: 'scroll-screen',
body: ListView.builder(
restorationId: 'list',
itemCount: 1000,
itemBuilder: (context, index) => ListTile(
title: Text('Item $index'),
),
),
);
}
}Test 1: Fails: This test fails, as when the screen state is restored, the scroll position is lost and is back at the item 0.
This test uses the AppGoRoute, which uses GoRouter internally to handle navigation.
testWidgets('restoration test go_router', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(
const RootRestorationScope(
restorationId: 'root',
child: AppGoRoute(),
),
);
expect(find.text('Item 0'), findsOneWidget);
expect(find.text('Item 500'), findsNothing);
await tester.scrollUntilVisible(
find.text('Item 100'),
10,
maxScrolls: 10000,
);
expect(find.text('Item 0'), findsNothing);
expect(find.text('Item 100'), findsOneWidget);
await tester.restartAndRestore();
// scroll position restored
expect(find.text('Item 0'), findsNothing); // <-- fails here
expect(find.text('Item 100'), findsOneWidget);
});Test 2: Passes.
This test uses AppSimple, same test content, and the test passes.
testWidgets('restoration test without go_router', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(
const RootRestorationScope(
restorationId: 'root',
child: AppSimple(),
),
);
expect(find.text('Item 0'), findsOneWidget);
expect(find.text('Item 500'), findsNothing);
await tester.scrollUntilVisible(
find.text('Item 100'),
10,
maxScrolls: 10000,
);
expect(find.text('Item 0'), findsNothing);
expect(find.text('Item 100'), findsOneWidget);
await tester.restartAndRestore();
// scroll position restored
expect(find.text('Item 0'), findsNothing);
expect(find.text('Item 100'), findsOneWidget);
});Logs
These are the test results:
/home/miquel/dev/tools/flutter/bin/flutter --no-color test --machine --start-paused test/widget_test.dart
Testing started at 16:17 ...
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure was thrown running a test:
Expected: no matching nodes in the widget tree
Actual: _TextFinder:<exactly one widget with text "Item 0" (ignoring offstage widgets): Text("Item
0", dependencies: [DefaultSelectionStyle, DefaultTextStyle, MediaQuery])>
Which: means one was found but none were expected
When the exception was thrown, this was the stack:
#4 main.<anonymous closure> (file:///home/miquel/tmp/go_route_push_shell/test/widget_test.dart:38:5)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)
This was caught by the test expectation on the following line:
file:///home/miquel/tmp/go_route_push_shell/test/widget_test.dart line 38
The test description was:
restoration test go_router
════════════════════════════════════════════════════════════════════════════════════════════════════
Test failed. See exception logs above.
The test description was: restoration test go_router
flutter analyze
Analyzing go_route_push_shell...
No issues found! (ran in 1.0s)
flutter doctor -v
[✓] Flutter (Channel stable, 3.3.10, on Ubuntu 22.04.1 LTS 5.15.0-56-generic, locale en_US.UTF-8)
• Flutter version 3.3.10 on channel stable at /home/miquel/dev/tools/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 135454af32 (12 days ago), 2022-12-15 07:36:55 -0800
• Engine revision 3316dd8728
• Dart version 2.18.6
• DevTools version 2.15.0
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
• Android SDK at /home/miquel/Android/Sdk
• Platform android-33, build-tools 33.0.1
• Java binary at:
/home/miquel/.local/share/JetBrains/Toolbox/apps/AndroidStudio/ch-0/213.7172.25.2113.9123335/jre/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)
• All Android licenses accepted.
[✓] Chrome - develop for the web
• Chrome at google-chrome
[✓] Linux toolchain - develop for Linux desktop
• Homebrew clang version 15.0.5
• cmake version 3.22.1
• ninja version 1.10.1
• pkg-config version 0.29.2
[✓] Android Studio (version 2021.3)
• Android Studio at /home/miquel/.local/share/JetBrains/Toolbox/apps/AndroidStudio/ch-0/213.7172.25.2113.9123335
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)
[✓] IntelliJ IDEA Community Edition (version 2022.3)
• IntelliJ at /home/miquel/.local/share/JetBrains/Toolbox/apps/IDEA-C/ch-0/223.8214.52
• Flutter plugin version 71.2.6
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
[✓] VS Code (version 1.66.2)
• VS Code at /usr/share/code
• Flutter extension version 3.40.0
[✓] VS Code
• VS Code at /snap/code/current
• Flutter extension version 3.40.0
[✓] Connected device (2 available)
• Linux (desktop) • linux • linux-x64 • Ubuntu 22.04.1 LTS 5.15.0-56-generic
• Chrome (web) • chrome • web-javascript • Google Chrome 108.0.5359.124
[✓] HTTP Host Availability
• All required HTTP hosts are available
• No issues found!