Yt100
Yt100

Reputation: 334

flutter return data from a screen error with pushNamed()

I use pushNamed() to get return data from screen like this:

_pushToPage2() async {
    String result = await Navigator.pushNamed(context, "/page2");
    print("$tag $result");
}

But there was something wrong with the code, this the full error stack trace:

E/flutter: [ERROR:flutter/shell/common/shell.cc(181)] Dart Error: Unhandled exception:
type 'MaterialPageRoute' is not a subtype of type 'Route'
0 NavigatorState._routeNamed (package:flutter/src/widgets/navigator.dart:1408:14)
1 NavigatorState.pushNamed (package:flutter/src/widgets/navigator.dart:1454:20)
2 _MyHomePageState._pushToPage2 (file:///Users/wang/flutter_project/flutter_navigation/lib/main.dart:113:50)
3 _MyHomePageState.build. (file:///Users/wang/flutter_project/flutter_navigation/lib/main.dart:58:19)
4 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
5 _InkResponseState.build. (package:flutter/src/material/ink_well.dart:562:30)
6 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
7 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
8 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:175:7)
9 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
10 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
11 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
12 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:143:19)
13 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:121:22)
14 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:101:7)
15 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:64:7)
16 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:48:7)
17 _invoke1 (dart:ui/hooks.dart:153:13)
18 _dispatchPointerDataPacket (dart:ui/hooks.dart:107:5)

But the following code is working properly:

_pushToPage2() async {
    String result = await Navigator.push(
         context, MaterialPageRoute(builder: (context) => Page2()));
    print("$tag $result");
}

Upvotes: 14

Views: 9147

Answers (5)

Schnodderbalken
Schnodderbalken

Reputation: 3477

None of the provided answers seem to address your issue as they advice you to abandon type safety by using dynamic or var. This is a bad workaround.

If you intent to use pushNamed while maintaining static typing, which you seem to want as you are providing the type String for the variable you want to store the result in, there is only one possibility: type casting.

So instead of using pushNamed() as a generic method like this:

_pushToPage2() async {
    String result = await Navigator.pushNamed<String>(context, "/page2");
    print("$tag $result");
}

you typecast the method result like this:

_pushToPage2() async {
    String result = await Navigator.pushNamed(context, "/page2") as String;
    print("$tag $result");
}

Not being able to provide a type to the pushNamed() method is a known deficiency of Navigator in combination with route tables, as stated here.

Upvotes: 1

Dai Xiao Wei
Dai Xiao Wei

Reputation: 91

I have a same problem. And finally I found a solution. Cast your result to your type.

For example:

String result = await Navigator.of(context).pushNamed("/some_route")

The code above will raise the exception.

But, you can do like this:

final result = await Navigator.of(context).pushNamed("/some_route") as String;

The code above will work as expected.

Upvotes: 9

Huy Dinh
Huy Dinh

Reputation: 33

Just declare the working type Page2 for MaterialPageRoute in the router

case "/page2":
  return MaterialPageRoute<Page2>(...};

Upvotes: 3

Laura
Laura

Reputation: 3383

For me, the error was a different one (type 'MaterialPageRoute<dynamic>' is not a subtype of type 'Route<String>'), and I solved it by declaring the returning value as a dynamic type:

dynamic result = await Navigator.of(context).pushNamed("/page");

While this loses some type safety, it works fine for me.

Upvotes: 16

ArgaPK
ArgaPK

Reputation: 455

In your main.dart file and inside your main Function define MaterialApp widget, and inside it we define routes (screens) of our App.

main.dart:

void main() {
  runApp( 
    new MaterialApp( 
      home: new Screen1(), 
      routes: <String, WidgetBuilder> { 
        '/screen1': (BuildContext context) => new Screen1(), 
        '/screen2' : (BuildContext context) => new Screen2() 
      },
    )
  );
}

Screen1:

class Screen1 extends StatelessWidget {
    @override
     Widget build(BuildContext context) {
        ...
      }
}

Screen2:

class Screen2 extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
       ...
    }
}

And to Navigate to screens we do:

Navigator.of(context).pushNamed('/screen2');

async and awiat is not needed but if you are doing async programming for e.g; you are querying Firestore and on the basis of the result of query, you choose to navigate to the new screen or choose to show the error.

For more details: routing and navigation in flutter

Edit:

To pass data between Screens, pass the argument to the Screen2 constructor and use Navigator.push(). Remember that in Navigator.pushNamed() you pass context and route name only, and you can't pass arguments in it.

 Navigator.push(context, new MaterialPageRoute(
              builder: (BuildContext context) => new Screen2(new Color(0xFF66BB6A)),
            ));

Screen2:

class Screen2 extends StatelessWidget {
     Screen2(this.color);
     final Color color;
      @override
      Widget build(BuildContext context) {
           ...
        }
 }

Upvotes: -2

Related Questions