web-dev-qa-db-fra.com

Problème avec Dart Futures dans Flutter: Échec de l'assertion: ligne 146: '<sortie optimisée>': n'est pas vraie

Je construis un module d'authentification d'utilisateur pour mon application et je rencontre des problèmes avec du code asynchrone.

Tout d'abord, voici l'erreur qui est lancée:

E/flutter (17162): [ERREUR: flutter/Shell/common/Shell.cc (188)] Erreur de fléchette: Exception non gérée: E/flutter (17162): 'Dart: async/future_impl.Dart': Échec de l'assertion: ligne 146: 'optimisé': n'est pas vrai . E/flutter (17162): # 0 _AssertionError._doThrowNew (Dart: core/runtime/liberrors_patch.Dart: 40: 39) E/flutter (17162): # 1 _AssertionError._throwNew (Dart: core/runtime/liberrors_patch.Dart: 36: 5) E/flutter (17162): # 2 _FutureListener.handleError (Dart: async/future_impl.Dart: 146: 14) E/flutter (17162): # 3 Future._propagateToListeners.handleError (Dart: async/future_impl.Dart: 654: 47) E/flutter (17162): # 4 Future._propagateToListeners (Dart: async/future_impl.Dart: 675: 24) E/flutter (17162): # 5 Future._completeError (Dart: async/future_impl.Dart: 494: 5) E/flutter (17162): # 6 _SyncCompleter._completeError (Dart: async/future_impl.Dart: 55: 12) E/flutter (17162): # 7 _Completer.completeError (Dart: async/future_impl.Dart: 27: 5) E/flutter (17162): # 8 _AsyncAwaitCompleter.completeError (Dart: async/exécution/libasync_patch.Dart: 40: 18) E/flutter (17162): # 9 FirebaseAuth.signInWithEmailAndPassword (package: firebase_auth/firebase_auth.Dart) E/flutter (17162): E/flutter (17162): # 10 Session.login. (package: mood_map/utilities/session.Dart: 31: 24) E/flutter (17162): # 11 _RootZone.runUnary (Dart: async/zone.Dart: 1379: 54) E/flutter (17162): # 12 _FutureListener.handleValue (Dart: async/future_impl.Dart: 129: 18) E/flutter (17162): # 13 Future._propagateToListeners.handleValueCallback (Dart: async/future_impl.Dart: 642: 45) E/flutter (17162): # 14 Future._propagateToListeners (Dart: async/future_impl.Dart: 671: 32) E/flutter (17162): # 15 Future._complete (Dart: async/future_impl.Dart: 476: 7) E/flutter (17162): # 16 _SyncCompleter.complete (Dart: async/future_impl.Dart: 51: 12) E/flutter (17162): # 17 _AsyncAwaitCompleter.complete (Dart: async/exécution/libasync_patch.Dart: 28: 18) E/flutter (17162): # 18 _completeOnAsyncReturn (Dart: async/runtime/libasync_patch.Dart: 295: 13) E/flutter (17162): # 19 Session._checkUserAlreadyExists (package: mood_map/utilities/session.Dart) E/flutter (17162): E/flutter (17162): # 20 Session.login (package: mood_map/utilities/session.Dart: 27: 11)

Et voici les fonctions impliquées:

static final FirebaseAuth _authenticator = FirebaseAuth.instance;

static void login(BuildContext context, String email, String password) async {

email = email.trim();
password = password.trim();

//Check if the user already exists
await _checkUserAlreadyExists(email).then((exists) {

  if(exists) {

    _authenticator.signInWithEmailAndPassword(email: email, password: password)
        .then((FirebaseUser user) { _loginSuccess(); })
        .catchError((Error e) { _loginFailure(context); });

  } else {

    Utilities.showMessageDialog(context, "That user doesn't exist. Please create an account below.");

  }

});

} 

----------------------------------------------------------------------

static Future createUserAccount(BuildContext context, email, String password) async {

//Check if the user already exists
await _checkUserAlreadyExists(email).then((exists) {

  if(exists) {

    Utilities.showMessageDialog(context, "That user already exists. Please login or select another account.");
    AppNavigator.navigateToLoginScreen();

  } else {

    _authenticator.createUserWithEmailAndPassword(email: email, password: password)
        .then((FirebaseUser user) { _createUserSuccess(); })
        .catchError((Error e) { _createUserFailure(context); });

  }

});

}

En bref, l'appel à _authenticator.signonWithEmailAndPassword () échoue. Je sais que l'instance _authenticator fonctionne avec d'autres fonctions, donc je sais que ce n'est pas un problème avec Firebase lui-même.

Je crains que je ne fasse quelque chose de mal en appelant une autre fonction asynchrone, _authenticator.signonWithEmailAndPassword () depuis une autre fonction asynchrone, _checkIfUserAlreadyExists (). Il semble que cela devrait être autorisé à partir d’un bloc .then () de ce que j’ai lu, mais le message d’erreur semble insister sur le fait qu’il est lié à la configuration de la nature asynchrone des appels de fonction.

Pensées?

3
chronic788

Si vous utilisez les clauses .then(), n'utilisez pas await.

.then() et await sont deux manières différentes de traiter les Future mais ne doivent pas être utilisés pour la même instance Future.

3
chemamolins

Pensez à utiliser async - wait pour corriger les erreurs de la «dernière étape». Cette réponse https://github.com/flutter/flutter/issues/22734 m'a beaucoup aidé.

Vous trouverez ci-dessous un extrait de code provenant d'une source dont je ne me souviens plus, mais qui m'a aidé à comprendre comment travailler correctement avec Future s. Je l'ai modifié un peu pour tester ma situation exacte (ajout des fonctions main4 () et divideFullAsyncNested ()). J'espère que ça aide.

// SO 29378453
import 'Dart:async';

import 'package:login_app/constants.Dart';

main() {
  // fails
  main1();
  main2();
  main3();
  main4();
}

Future<double> divide(int a, b) {
  // this part is still sync
  if (b == 0) {
    throw new Exception('Division by zero divide non-async');
  }
  // here starts the async part
  return new Future.value(a / b);
}

Future<double> divideFullAsync(int a, b) {
  return new Future(() {
    if (b == 0) {
      throw new Exception('Division by zero full async');
    }
    return new Future.value(a / b);
    // or just
    // return a / b;
  });
}

Future<double> divideFullAsyncNested() {
  return divideFullAsync(7, 8).then(
    (val) {
      return divideFullAsync(5, 0).then(
        (val2) {
          return Future(() {
            if (val2 == 1) {
              throw Exception('Innermost: Result not accepted exception.');
            }
            return val2;
          });
        },
      ).catchError((err) => throw Exception('Inner:    $err'));
    },
  ).catchError((err) => throw Exception('Outter: $err'));
}

//Future<double> divideFullAsyncNested() {
//  return divideFullAsync(9, 9).then(
//    (val) {
//      return Future(
//        () {
//          if (val == 1) {
//            throw Exception('Result not accepted exception.');
//          }
//          return val;
//        },
//      );
//    },
//  ).catchError((err) => throw Exception(err.toString()));
//}

// async error handling doesn't catch sync exceptions

void main1() async {
  try {
//    divide(1, 0).then((result) => print('(1) 1 / 0 = $result')).catchError(
//        (error) => print('(1)Error occured during division: $error'));
    var result = await divide(1, 0);
    print('(1) 1 / 0 = $result');
  } catch (ex) {
    print('(1.1)Error occured during division: ${ex.toString()}');
  }
}

// async error handling catches async exceptions
void main2() {
  divideFullAsync(1, 0)
      .then((result) => print('(2) 1 / 0 = $result'))
      .catchError(
          (error) => print('(2) Error occured during division: $error'));
}

// async/await allows to use try/catch for async exceptions
main3() async {
  try {
    await divideFullAsync(1, 0);
    print('3');
  } catch (error) {
    print('(3) Error occured during division: $error');
  }
}

main4() async {
//  try {
//    await divideFullAsyncNested();
//  } on Exception catch (e) {
//    print("(4) ${e.toString().replaceAll('Exception:', '').trimLeft().trimRight()}");
//  }
  try {
    divideFullAsyncNested()
        .then((v) => print(v))
        .catchError((err) => print(Constants.refinedExceptionMessage(err)));
  } on Exception catch (e) {
    print("(4) ${Constants.refinedExceptionMessage(e)}");
  }
}
1
Mitch