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
Navigator 2.0 can't provide initial page #71106
Comments
Issue replicable on latest beta and on latest master. Error log
beta and master flutter doctor -v
@wreppun FYI I see below exception also:
|
Related to 65777 |
@darshankawar I saw that exception too, but I think that's an artifact of the earlier exception? Both exceptions disappear when an initial page is used. |
I think there are two issues here:
For now, you can workaround this by building some default route when route stack is empty. |
Removed the web label as this doesn't look web-specific. |
I have a Whenever I navigate to it, this error is thrown. I wasn't able to determine if this is the same issue or if I should create a new one. The error is non-breaking, but shows up on console. I solved the error by adding this: |
if you return synchronous future, you will want to remove the async keyword in the function, otherwise it still turns it into a async future. Something like this will work. If the logic does have to be async, you will need to handle the case where the build is called before the parsing finishes. I will update the error message Codeimport 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(ElephantCowApp());
}
class ElephantCowApp extends StatefulWidget {
@override
_ElephantCowAppState createState() => _ElephantCowAppState();
}
class _ElephantCowAppState extends State<ElephantCowApp> {
final _publicRouter = ElephantCowRouterDelegate();
final _routeParser = PublicRouteInformationParser();
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerDelegate: _publicRouter,
routeInformationParser: _routeParser,
);
}
}
/// Expand to ADT or Class/Subclasses as needed
@immutable
class ElephantCowPath {
final bool isElephant;
final bool isCow;
ElephantCowPath.elephant()
: isElephant = true,
isCow = false;
ElephantCowPath.cow()
: isElephant = false,
isCow = true;
T caseMap<T>({
@required T Function() onElephant,
@required T Function() onCow,
}) {
if (isElephant) {
return onElephant();
}
if (isCow) {
return onCow();
}
throw UnimplementedError('Case not handled in path $this');
}
@override
bool operator ==(Object other) {
if (other is ElephantCowPath) {
if (isElephant && other.isElephant) {
return true;
}
if (isCow && other.isCow) {
return true;
}
}
return false;
}
@override
String toString() {
return caseMap(
onCow: () => 'Path: cow',
onElephant: () => 'Path: elephant',
);
}
}
class ElephantPage extends Page<ElephantCowPath> {
ElephantPage() : super(key: ValueKey('elephant'));
@override
Route<ElephantCowPath> createRoute(BuildContext context) {
return MaterialPageRoute(
settings: this,
builder: (_) => Scaffold(
body: Center(
child: Text('I am an elephant'),
),
),
);
}
}
class CowPage extends Page<ElephantCowPath> {
CowPage() : super(key: ValueKey('cow'));
@override
Route<ElephantCowPath> createRoute(BuildContext context) {
return MaterialPageRoute(
settings: this,
builder: (_) => Scaffold(
body: Center(
child: Text('I am a cow. Moo.'),
),
),
);
}
}
class ElephantCowRouterDelegate extends RouterDelegate<ElephantCowPath>
with ChangeNotifier, PopNavigatorRouterDelegateMixin<ElephantCowPath> {
final _navigatorKey = GlobalKey<NavigatorState>();
final routeStack = <ElephantCowPath>[];
@override
ElephantCowPath get currentConfiguration =>
routeStack.isNotEmpty ? routeStack.last : null;
@override
Widget build(BuildContext context) {
print('building router');
return Navigator(
key: _navigatorKey,
pages: [
...routeStack.map(_buildPage),
],
onPopPage: (route, dynamic result) {
if (!route.didPop(result)) {
return false;
}
return true;
},
);
}
@override
Future<void> setInitialRoutePath(ElephantCowPath path) {
print('set initial route path');
return setNewRoutePath(path);
}
@override
Future<void> setNewRoutePath(ElephantCowPath path) {
print('setting new path: $path');
if (routeStack.isEmpty || routeStack.last != path) {
print('added path');
routeStack.add(path);
} else {
print('skipped add path');
}
return SynchronousFuture(null);
}
@override
GlobalKey<NavigatorState> get navigatorKey => _navigatorKey;
static Page<ElephantCowPath> _buildPage(ElephantCowPath p) {
return p.caseMap(
onElephant: () => ElephantPage(),
onCow: () => CowPage(),
);
}
}
class PublicRouteInformationParser
extends RouteInformationParser<ElephantCowPath> {
@override
Future<ElephantCowPath> parseRouteInformation(
RouteInformation routeInformation,
) {
return SynchronousFuture(_parsePublicPath(routeInformation.location));
}
static ElephantCowPath _parsePublicPath(String location) {
final uri = Uri.parse(location);
// Handle '/'
if (uri.pathSegments.length == 0) {
print('parsed: root');
return ElephantCowPath.elephant();
}
// Handle '/post/:id'
if (uri.pathSegments.length == 1) {
if (uri.pathSegments.first == 'elephant') {
print('parsed: elephant');
return ElephantCowPath.elephant();
}
if (uri.pathSegments.first == 'cow') {
print('parsed: cow');
return ElephantCowPath.cow();
}
}
// Handle unknown routes
print('parsed: unknown ${uri.pathSegments.join('/')}');
return ElephantCowPath.elephant();
}
@override
RouteInformation restoreRouteInformation(ElephantCowPath path) {
print('restoring route info - $path');
return path.caseMap(
onCow: () => RouteInformation(location: '/cow'),
onElephant: () => RouteInformation(location: '/elephant'),
);
}
} |
I ran into this same error, no idea why it's happening as I'm just trying to set Something like:
In the end I just went straight to the source and manually injected my own initial route if "/" is reported:
|
@esDotDev |
Thank you for the example here @chunhtai Removing the async keyword from Posting the errors here to help future users who are searching for a solution. Error:
Fixed
|
@chunhtai
|
@mtgnoah If the logic does have to be async, you will need to handle the case where the build is called before the parsing finishes. |
How would I handle that case? Should I implement a route that is just a loading screen with circularprogressindicator? |
@chunhtai Also just letting you know that Parse is the backend and that is what I am awaiting on. It's not parsing anything. |
Unhandled Exception: Null check operator used on a null value This is the error I am receiving by the way. |
final ParseResponse parseResponse = |
This worked! For anyone with the same issue on accessing backend
|
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of |
Steps to Reproduce
flutter create bug
.main.dart
flutter run -d chrome
Expected results:
Navigator 2.0 loads the initial page based on the browser url.
Actual results:
Navigator 2.0 throws an error before it attempts to parse the url.
More info
Based on its name and the documentation around the
build
method on RouterDelegate, I would expectsetInitialRoutePath
to set the initial Path.Instead, if
Navigator.pages
is initially empty, the Navigator attempts to use onGenerateRoute to create the initial route. If I'm using Navigator 2.0, I wouldn't expect to implement onGenerateRoute.Workarounds
I can add a temporary initial route, and remove it as soon as I parse the url, but that seems fairly convoluted for a pretty basic case.
Doctor
Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel beta, 1.24.0-10.2.pre, on Mac OS X 10.15.7 19H15 darwin-x64, locale en-US) [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) [!] Xcode - develop for iOS and macOS (Xcode 12.1) ! CocoaPods 1.8.3 out of date (1.9.0 is recommended). CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that responds to your plugin usage on the Dart side. Without CocoaPods, plugins will not work on iOS or macOS. For more info, see https://flutter.dev/platform-plugins To upgrade see https://guides.cocoapods.org/using/getting-started.html#installation for instructions. [✓] Chrome - develop for the web [✓] Android Studio (version 4.1) [✓] VS Code (version 1.51.1) [✓] Connected device (2 available)The text was updated successfully, but these errors were encountered: