Flutter – Navigator.pushNamed makes app crash when calling a route ( inside a FutureBuilder )

huangapple go评论75阅读模式
英文:

Flutter - Navigator.pushNamed makes app crash when calling a route ( inside a FutureBuilder )

问题

以下是您要翻译的内容:

So basically i'm working on a currency app, and after you charge your account with app currency i verified if the payment as been done or not i need to redirect to the home page but it crashes every time, when all the other custom route are working.

app.dart : (this are my routes)

navigatorKey: _navigatorKey,
        initialRoute: '/',
        routes: {
          '/register': (context) => RegisterScreen(),
          '/login': (context) => LoginScreen(),
          '/home': (context) => HomeScreen(),
          '/info': (context) => InfoPage(),
          '/accueil': (context) => Onboarding(),
          '/wallet' : (context) => WalletScreenContainer(),
        },

confirmation.dart page is where I check the state of the payment by calling an API that's working perfectly:

import 'package:corsicoin/src/models/transaction.dart';
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../home_screen.dart';

import '../../auth/auth.dart';
import '../../lang/lang.dart';
import '../shared/current_credit.dart';

class Confirmation extends StatefulWidget {
  final String transactionToken;
  @override
  Confirmation(this.transactionToken);

  _ConfirmationState createState() => _ConfirmationState();
}

class _ConfirmationState extends State<Confirmation> with SingleTickerProviderStateMixin {
  String get transactionToken => widget.transactionToken;
  AuthBloc _authBloc;
  Future<String> _asyncFetch;

  @override
  void initState() {
    print('token : '+transactionToken);
    _authBloc = BlocProvider.of<AuthBloc>(context);
    _asyncFetch = getPaymentDetails(transactionToken);
    super.initState();
  }

  @override
	void dispose(){
    this.dispose;
	  super.dispose();
	}

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Confirmation"),
      ),
      body: buildPage()
    );
  }

  Widget buildPage() {
    return FutureBuilder<String>(
      future: _asyncFetch,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          if(snapshot.data == "true"){
            return Container( 
              padding: EdgeInsets.fromLTRB(30,50,30,150),
              child : Column(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                Center(child : LocalizedText(Localization.payment_done, textAlign: TextAlign.center,)),
                Center(child :Icon(
                  Icons.check_circle_outline,
                  color: Colors.green,
                  size : 100,
                )),
                MaterialButton(
                  minWidth: 500,
                  color: Theme.of(context).primaryColor,
                  textColor: Colors.white,
                  padding: EdgeInsets.all(12),
                  child: LocalizedText(Localization.ok_understood,),
                  onPressed: (){
                    Navigator.pushNamed(context, '/home');
                  },
                ),
              ],
              )
            );
          } else {
            return Container( 
              padding: EdgeInsets.fromLTRB(30,50,30,150),
              child : Column(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                Center(child : LocalizedText(Localization.payment_failed, textAlign: TextAlign.center,)),
                Center(child :Icon(
                  Icons.block,
                  color: Colors.red,
                  size : 100,
                )),
                MaterialButton(
                  minWidth: 500,
                  color: Theme.of(context).primaryColor,
                  textColor: Colors.white,
                  padding: EdgeInsets.all(12),
                  child: LocalizedText(Localization.ok_understood,),
                  onPressed: (){
                    print("yo");
                  },
                ),
              ],
              )
            );
          }
        } else if (snapshot.hasError) {
          return Scaffold(
            body: Center(
              child: Text("${snapshot.error}"),
            ),
          );
        }
        return Scaffold(
          body: 
          Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              Container(padding: EdgeInsets.all(50),
                child : LocalizedText(Localization.wait_payment, textAlign: TextAlign.center,),),
              Center(child : CircularProgressIndicator()),
          ]),
        );
      },
    );
  }

  Future<String> getPaymentDetails(String token) async {
    final confirmationBool = await _authBloc.authRepository.getPaymentDetails(token);
    print("bool returned : "+confirmationBool);
    return confirmationBool;
  }
}

And when I tap on the RaisedButton the app crashes.

home_screen.dart:

import 'package:flutter/material.dart';

import 'pay/pay_screen.dart';
import 'cash/cash_screen.dart';
import 'shops/shops_screen.dart';
import 'account/account_screen.dart';
import 'account/shop_account_screen.dart';
import 'transfer/transfer_screen.dart';
import 'wallet/wallet_screen.dart';
import '../lang/lang.dart';

class HomeScreen extends StatefulWidget {
  final bool isShop;
  HomeScreen({this.isShop});
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  List<Widget> _widgets;
  int _currentIndex = 2;

  bool get isShop => widget.isShop;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    _widgets = isShop
        ? [
            ShopAccountScreen(),
            ShopsScreen(),
            CashScreenContainer(),
            PayScreenContainer(),
            TransferScreen(),
          ]
        : [
            WalletScreenContainer(),
            ShopsScreen(),
            PayScreenContainer(),
            TransferScreen(),
            AccountScreen(),
          ];

    return Scaffold(
      body: _widgets.elementAt(_currentIndex),
      bottomNavigationBar: NavigationBar(
        currentIndex: _currentIndex,
        isShop: isShop,
        onTap: (int index) {
          setState(() {
            _currentIndex = index;
          });
        },
      ),
      resizeToAvoidBottomInset: _currentIndex != 2 || _currentIndex != 3,
    );
  }
}

class NavigationBar extends StatelessWidget {
  final int currentIndex;
  final void Function(int index) onTap;
  final bool isShop;
  NavigationBar({this.currentIndex, this.onTap, this.isShop});

  @override
  Widget build(BuildContext context) {
    return isShop
        ? _buildNavigationBarForShop(context)
        : _buildNavigationBarForUser(context);
  }

  Widget _buildNavigationBarForUser(BuildContext context) {
    return BottomNavigationBar(
      items: [
        BottomNavigationBarItem(
          icon: Icon(Icons.account_balance_wallet),
          title: LocalizedText(Localization.menu_wallet),
          backgroundColor: Colors.white,
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.shopping_cart),
          title: LocalizedText(Localization.menu_shops),
          backgroundColor: Colors.white,
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.credit_card),
          title: LocalizedText(Localization.menu_pay),
          backgroundColor: Colors.white,
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.swap_horiz),
          title: LocalizedText(Localization.menu_transfer),
          backgroundColor: Colors.white,
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.person),
          title: LocalizedText(Localization.menu_account),
          backgroundColor: Colors.white,
        ),
      ],
      currentIndex: currentIndex,
      type: BottomNavigationBarType.fixed,
      onTap: onTap,
    );
  }

  Widget _buildNavigationBarForShop(BuildContext

<details>
<summary>英文:</summary>

So basically i&#39;m working on a currency app, and after you charge your account with app currency i verified if the payment as been done or not i need to redirect to the home page but it crashes every time, when all the other custom route are working.

app.dart : (this are my routes)

navigatorKey: _navigatorKey,
initialRoute: '/',
routes: {
'/register': (context) => RegisterScreen(),
'/login': (context) => LoginScreen(),
'/home': (context) => HomeScreen(),
'/info': (context) => InfoPage(),
'/accueil': (context) => Onboarding(),
'/wallet' : (context) => WalletScreenContainer(),
},


the confirmation.dart page is where I check the state of the payment by calling an API that&#39;s working perfectly :

import 'package:corsicoin/src/models/transaction.dart';
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../home_screen.dart';

import '../../auth/auth.dart';
import '../../lang/lang.dart';
import '../shared/current_credit.dart';

class Confirmation extends StatefulWidget {
final String transactionToken;
@override
Confirmation(this.transactionToken);

_ConfirmationState createState() => _ConfirmationState();
}

class _ConfirmationState extends State<Confirmation> with SingleTickerProviderStateMixin {
String get transactionToken => widget.transactionToken;
AuthBloc _authBloc;
Future<String> _asyncFetch;

@override
void initState() {
print('token : '+transactionToken);
_authBloc = BlocProvider.of<AuthBloc>(context);
_asyncFetch = getPaymentDetails(transactionToken);
super.initState();
}

@override
void dispose(){
this.dispose;
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Confirmation"),//LocalizedText(Localization.payment),
// leading: null,
// automaticallyImplyLeading: false,
),
body: buildPage()
);
}

Widget buildPage() {
return FutureBuilder<String>(
// _initiatepayment() will await for the url sended bck by Cyclos
future: _asyncFetch,
builder: (context, snapshot) {
if (snapshot.hasData) {
if(snapshot.data == "true"){
//this will be what is returned if the payment is successful
return Container(
padding: EdgeInsets.fromLTRB(30,50,30,150),
child : Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Center(child : LocalizedText(Localization.payment_done, textAlign: TextAlign.center,)),
Center(child :Icon(
Icons.check_circle_outline,
color: Colors.green,
size : 100,
)),
MaterialButton(
minWidth: 500,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
padding: EdgeInsets.all(12),
child: LocalizedText(Localization.ok_understood,),
onPressed: (){
Navigator.pushNamed(context, '/home');
},
),
],
)
);
} else {
//this is waht we return if the payment failed
return Container(
padding: EdgeInsets.fromLTRB(30,50,30,150),
child : Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Center(child : LocalizedText(Localization.payment_failed, textAlign: TextAlign.center,)),
Center(child :Icon(
Icons.block,
color: Colors.red,
size : 100,
)),
MaterialButton(
minWidth: 500,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
padding: EdgeInsets.all(12),
child: LocalizedText(Localization.ok_understood,),
onPressed: (){
print("yo");
},
),
],
)
);
}
} else if (snapshot.hasError) {
return Scaffold(
body: Center(
child: Text("${snapshot.error}"),
),
);
}
return Scaffold(
body:
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(padding: EdgeInsets.all(50),
child : LocalizedText(Localization.wait_payment, textAlign: TextAlign.center,),),
Center(child : CircularProgressIndicator()),
]),
);
},
);
}

Future<String> getPaymentDetails(String token) async {
final confirmationBool = await _authBloc.authRepository.getPaymentDetails(token);
print("bool returned : "+confirmationBool);
return confirmationBool;
}
}


And when I tap on the RaisedButton the app crashes.
So is it because of the Future Builder or is it because the /home page ask for a parameters but it has already been build before even getting to the confirmation page. here is the code if you want : 
home_screen.dart : 

import 'package:flutter/material.dart';

import 'pay/pay_screen.dart';
import 'cash/cash_screen.dart';
import 'shops/shops_screen.dart';
import 'account/account_screen.dart';
import 'account/shop_account_screen.dart';
import 'transfer/transfer_screen.dart';
import 'wallet/wallet_screen.dart';
import '../lang/lang.dart';

class HomeScreen extends StatefulWidget {
final bool isShop;
HomeScreen({this.isShop});
_HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
List<Widget> _widgets;
int _currentIndex = 2;

bool get isShop => widget.isShop;

@override
void initState() {
super.initState();
}

@override
Widget build(BuildContext context) {
_widgets = isShop
? [
ShopAccountScreen(),
ShopsScreen(),
CashScreenContainer(),
PayScreenContainer(),
TransferScreen(),
]
: [
WalletScreenContainer(),
ShopsScreen(),
PayScreenContainer(),
TransferScreen(),
AccountScreen(),
];

return Scaffold(
body: _widgets.elementAt(_currentIndex),
bottomNavigationBar: NavigationBar(
currentIndex: _currentIndex,
isShop: isShop,
onTap: (int index) {
setState(() {
_currentIndex = index;
});
},
),
resizeToAvoidBottomInset: _currentIndex != 2 || _currentIndex != 3,
);

}
}

class NavigationBar extends StatelessWidget {
final int currentIndex;
final void Function(int index) onTap;
final bool isShop;
NavigationBar({this.currentIndex, this.onTap, this.isShop});

@override
Widget build(BuildContext context) {
return isShop
? _buildNavigationBarForShop(context)
: _buildNavigationBarForUser(context);
}

Widget _buildNavigationBarForUser(BuildContext context) {
return BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.account_balance_wallet),
title: LocalizedText(Localization.menu_wallet),
backgroundColor: Colors.white,
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_cart),
title: LocalizedText(Localization.menu_shops),
backgroundColor: Colors.white,
),
BottomNavigationBarItem(
icon: Icon(Icons.credit_card),
title: LocalizedText(Localization.menu_pay),
backgroundColor: Colors.white,
),
BottomNavigationBarItem(
icon: Icon(Icons.swap_horiz),
title: LocalizedText(Localization.menu_transfer),
backgroundColor: Colors.white,
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
title: LocalizedText(Localization.menu_account),
backgroundColor: Colors.white,
),
],
currentIndex: currentIndex,
type: BottomNavigationBarType.fixed,
// backgroundColor: Colors.white,
// selectedItemColor: Theme.of(context).primaryColor,
// unselectedItemColor: Theme.of(context).colorScheme.secondary,
onTap: onTap,
);
}

Widget _buildNavigationBarForShop(BuildContext context) {
return BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.business_center),
title: LocalizedText(Localization.menu_account),
backgroundColor: Colors.white,
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_cart),
title: LocalizedText(Localization.menu_shops),
backgroundColor: Colors.white,
),
BottomNavigationBarItem(
icon: Icon(Icons.arrow_downward),
title: LocalizedText(Localization.menu_cash),
backgroundColor: Colors.white,
),
BottomNavigationBarItem(
icon: Icon(Icons.credit_card),
title: LocalizedText(Localization.menu_pay),
backgroundColor: Colors.white,
),
BottomNavigationBarItem(
icon: Icon(Icons.swap_horiz),
title: LocalizedText(Localization.menu_transfer),
backgroundColor: Colors.white,
),
],
currentIndex: currentIndex,
type: BottomNavigationBarType.fixed,
onTap: onTap,
);
}
}

name: corsicoin
description: Corsicoin app.

The following defines the version and build number for your application.

A version number is three numbers separated by dots, like 1.2.43

followed by an optional build number separated by a +.

Both the version and the builder number may be overridden in flutter

build by specifying --build-name and --build-number, respectively.

In Android, build-name is used as versionName while build-number used as versionCode.

Read more about Android versioning at https://developer.android.com/studio/publish/versioning

In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.

Read more about iOS versioning at

https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html

version: 0.1.46

environment:
sdk: ">=2.1.0 <3.0.0"

dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter

The following adds the Cupertino Icons font to your application.

Use with the CupertinoIcons class for iOS style icons.

cupertino_icons: ^0.1.2

shared_preferences: ^0.5.2
cached_network_image: ^1.1.0
flutter_svg: ^0.13.1
rflutter_alert: ^1.0.3
flutter_bloc: ^0.11.1
equatable: ^0.1.6
flutter_secure_storage: ^3.2.1
local_auth: ^0.4.0+1
http_auth: ^0.2.5
firebase_core: ^0.4.0+6
firebase_messaging: ^5.1.3
cloud_firestore: ^0.12.9+6
firebase_auth: ^0.14.0+5
validate: ^1.7.0
kiwi: ^0.1.0
image_picker: ^0.6.1
flutter_crashlytics: ^1.0.0
flutter_sticky_header: ^0.4.0
dio: ^2.1.0
auto_size_text: ^1.1.1
flutter_masked_text: ^0.8.0
permission_handler: '^3.2.0'
path_provider: ^0.5.0+1
flutter_email_sender: ^2.0.0
flutter_swiper: ^1.1.6
contacts_service: ^0.2.8
geolocator: ^5.1.1+1
google_maps_flutter: ^0.5.20+1
url_launcher: ^5.0.2
qr_mobile_vision: ^0.2.2
qr_flutter: ^2.0.0+51
csv: ^4.0.3
share_extend: ^1.0.8
country_pickers: ^1.1.0
diacritic: ^0.1.1
recase: ^2.0.1
keyboard_visibility: ^0.5.6

http: 0.12.0
flutter_webview_plugin: ^0.3.10
webview_flutter : ^0.3.17

flutter_worldpay:
path: ../flutter_worldpay/

dev_dependencies:
flutter_test:
sdk: flutter

For information on the generic Dart part of this file, see the

following page: https://www.dartlang.org/tools/pub/pubspec

The following section is specific to Flutter.

flutter:

assets:
- assets/images/
- assets/icons/
- assets/html/

The following line ensures that the Material Icons font is

included with your application, so that you can use the icons in

the material Icons class.

uses-material-design: true

To add assets to your application, add an assets section, like this:

- images/a_dot_ham.jpeg

An image asset can refer to one or more resolution-specific "variants", see

https://flutter.io/assets-and-images/#resolution-aware.

For details regarding adding assets from package dependencies, see

https://flutter.io/assets-and-images/#from-packages

To add custom fonts to your application, add a fonts section here,

in this "flutter" section. Each entry in this list should have a

"family" key with the font family name, and a "fonts" key with a

list giving the asset and other descriptors for the font. For

example:

fonts:

- family: Schyler

fonts:

- asset: fonts/Schyler-Regular.ttf

- asset: fonts/Schyler-Italic.ttf

style: italic

- family: Trajan Pro

fonts:

- asset: fonts/TrajanPro.ttf

- asset: fonts/TrajanPro_Bold.ttf

weight: 700

For details regarding fonts from package dependencies,

see https://flutter.io/custom-fonts/#from-packages

fonts:
- family: Lato
fonts:
- asset: assets/fonts/Lato.ttf
- asset: assets/fonts/Lato-Light.ttf
weight: 300
- asset: assets/fonts/Lato-Bold.ttf
weight: 700
- family: Nunito
fonts:
- asset: assets/fonts/Nunito.ttf
- asset: assets/fonts/Nunito-Light.ttf
weight: 300
- asset: assets/fonts/Nunito-Bold.ttf
weight: 700


And everything is on point in flutter doctor
</details>
# 答案1
**得分**: 0
导致崩溃的最可能原因似乎是`HomeScreen`中的`isShop`布尔值。
以下是原因:
- `isShop`是一个可选的布尔值,这意味着如果没有明确赋值,它将保持为`null`。
- 'isShop'在`initState`中未经初始化即被使用,以处理默认情况。
要解决此问题,只需将以下部分替换为:
```dart
HomeScreen({this.isShop});

替换为

HomeScreen({this.isShop = false});

如果需要更多帮助,请告诉我。

英文:

The most probable cause of the crash seems to be isShop boolean value in HomeScreen.

Following are the reasons:

  • isShop is an optional bool value, which means, it will remain null if not explicitly given a value
  • 'isShop' is used without being initialized in the initState to handle default scenario

To resolve this just replace:

HomeScreen({this.isShop});

with

HomeScreen({this.isShop = false});

let me know if you need more help.

答案2

得分: 0

"不,没事,我找到了解决方法,通过在我的代码中传递参数:\nNavigator.of(context).pop(true) //如果我想要的结果是好的\n\n或\n\nNavigator.of(context).pop('error') //如果我想要的结果是不好的"

英文:

No it's ok i found a solution by passing parameters in my :

Navigator.of(context).pop(true) //if what i wanted to happen is good
or 
Navigator.of(context).pop(&#39;error&#39;) //if what i wanted to happen went bad

huangapple
  • 本文由 发表于 2020年1月6日 21:44:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/59613216.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定