Flutter error : Null check operator used on a null value


Avatar de Pierre Courtois

Dans ce guide, je vous explique pourquoi le message « Null check operator used on a null value » apparaît et comment le résoudre.


null check operator Flutter

Pourquoi le message d’erreur “Null check operator used on a null value” apparaît-il ? 

Le message d’erreur « Null check operator used on a null value » est un message d’erreur de Flutter qui se produit lorsque vous utilisez l’opérateur de vérification de nullité “!” sur une valeur qui s’avère être nulle. 

Pour comprendre un peu mieux le problème, voici les deux opérateurs de nullité, fournis par Flutter :

  • ! (point d’exclamation) : Assure que la valeur n’est jamais nulle.
  • ?. (point d’interrogation) : Vérifie si la valeur est nulle avant d’y accéder. Si elle est nulle, il renvoie null ou une valeur par défaut.

Puisque vous essayez d’accéder à une propriété ou d’appeler une méthode sur une variable qui n’a pas de valeur et qui portant est déclarée non null “!”, le code se bloque et ce message apparaît.

Par exemple, voici un code d’exemple faisant apparaître ce message d’erreur : 

String? nom; // Déclaration d'une variable nullable
print(nom!.length); // Erreur "Null check operator used on a null value" car `nom` peut être null

Ici, nom est déclaré comme pouvant avoir une valeur null (opérateur “?” ajouté à ma classe String). Or, dans ma méthode print(), nom est déclaré comme non-nullable via l’opérateur “!”. Ma variable nom pouvant être nulle et n’ayant pas de valeur actuellement, le message d’erreur « Null check operator used on a null value » s’affiche donc. 

Qu’est-ce qu’une valeur null en dart ?

En dart, une valeur nulle représente l’absence de valeur d’une variable. Attention toutefois, une variable “” ne correspond pas à une valeur nulle. En effet, celle-ci est tout simplement assimilée à une chaîne vide, indiquant l’absence de caractères, mais pas une valeur nulle.

Comment régler le message d’erreur “Null check operator used on a null value”

Il existe plusieurs manières de résoudre ce message d’erreur, soit en changeant d’opérateur, en attribuant une valeur à votre variable, ou en utilisant la méthode catch.

Changer d’opérateur de vérification de nullité 

La première chose que vous pouvez faire pour régler ce problème est de changer l’opérateur de nullité de votre méthode : 

String? nom;
print(nom?.length ?? 0); // Afficher 0 si nom est null, sinon afficher la longueur de nom

Ici, j’indique que ma variable nom peut avoir une valeur nulle via l’opérateur “?”. J’indique également quelle valeur lui donner, le cas échéant, ici 0. 

Donner une valeur à votre variable 

Ce message d’erreur apparaissant lorsqu’une variable est nulle, une autre solution pour éviter ce problème est de toujours donner une valeur par défaut à vos variables : 

String nom = ""; 
print(nom.length); 

Ici, j’attribue une chaîne de caractère vide, comme valeur à ma variable nom. Je n’ai donc pas de message d’erreur au moment de l’afficher dans la console. 

Utiliser la méthode try & catch

Utiliser une méthode try & catch, n’empêchera pas d’avoir une erreur si votre valeur est null, mais permettra au moins au code de ne pas se bloquer et de devoir relancer l’application. Je vous conseille donc d’en user le plus possible lorsque vous mettez en place des fonctions qui peuvent renvoyer une erreur : 

String? nom;

try {
  print(nom!.length); 
} catch (e) {
  print("Erreur : $e"); // Afficher le message d'erreur
}

Ici, j’essaye d’afficher la longueur de ma variable nom dans ma méthode try. Mais celle-ci n’a pas de valeur. J’ai donc mis en place une méthode catch, qui va renvoyer un message d’erreur dans ma console et quitter ma méthode, plutôt que de bloquer l’application. 

Quand puis-je avoir une erreur de type null check operator ?

L’erreur null check operator, peut subvenir avec tout un tas de widgets différents. En voici quelques exemples.

Erreur avec Navigator ou MediaQuery

Cette erreur se produit souvent lorsque vous accédez à un BuildContext de manière asynchrone, sans vérifier si le widget est toujours monté.

Future<void> foo() async {
  // Opération asynchrone
  await compute();  

  // Accès à 'context' sans vérification
  MediaQuery.of(context).size;
  Navigator.of(context).pop();
}

Solution

Avant d’accéder au contexte, vérifiez si le widget est toujours monté à l’aide de la propriété mounted :

Future<void> foo() async {
  await compute();  

  // Vérifiez si le widget est monté
  if (mounted) {
    MediaQuery.of(context).size;
    Navigator.of(context).pop();  
  }
}

Erreur avec Colors

Une autre erreur fréquente survient lorsque vous essayez d’accéder à une nuance inexistante d’une couleur, comme :

Colors.blueAccent.shade60

Dans le code source de Flutter, cette opération utilise le null check operator, ce qui peut provoquer une erreur si la nuance demandée n’existe pas :

Color get shade50 => this[60]!; // <-- Opérateur "!"

Solution

Avant d’accéder au contexte, vérifiez si le widget est toujours monté à l’aide de la propriété mounted :

Future<void> foo() async {
  await compute();  

  // Vérifiez si le widget est monté
  if (mounted) {
    MediaQuery.of(context).size;
    Navigator.of(context).pop();  
  }
}

Erreur avec FutureBuilder ou StreamBuilder

Lorsque vous travaillez avec des FutureBuilder ou StreamBuilder, l’erreur peut apparaître si vous ne spécifiez pas de type ou si vous manipulez incorrectement les données.

Solution 1 : Spécifiez un type explicite

Déclarez le type des données attendues dans le FutureBuilder ou StreamBuilder :

FutureBuilder<List<int>>( // Type explicitement défini
  future: _listOfInt(),
  builder: (_, snapshot) {
    if (snapshot.hasData) {
      List<int> myList = snapshot.data!; // Données sécurisées
    }
    return Container();
  },
)

Solution 2 : Utilisez as pour caster les données

Vous pouvez également caster les données pour éviter l’erreur :

FutureBuilder(
  future: _listOfInt(),
  builder: (_, snapshot) {
    if (snapshot.hasData) {
      var myList = snapshot.data! as List<int>; // Cast explicite
    }
    return Container();
  },
)

Erreur avec TextEditingController

Lors de l’utilisation de TextEditingController pour des champs de texte, l’erreur peut apparaître si vous essayez d’accéder à une propriété après avoir détruit le contrôleur.

@override
void dispose() {
  _textController.dispose();
  print(_textController.text); // Erreur !
  super.dispose();
}

Solution

Ne tentez pas d’utiliser le contrôleur après avoir appelé dispose :

@override
void dispose() {
  print(_textController.text); // Utilisation avant `dispose`
  _textController.dispose();
  super.dispose();
}

Erreur avec List ou Map nullables

Les collections peuvent également provoquer cette erreur si vous utilisez l’opérateur ! sur une clé ou un index potentiellement null :

List<String>? myList;
String value = myList![0]; // Erreur si `myList` est null

Solution

Vérifiez la nullité avant d’accéder à l’élément :

if (myList != null && myList.isNotEmpty) {
  String value = myList[0];
}

Erreur avec GlobalKey

Lorsque vous utilisez un GlobalKey pour accéder à l’état d’un widget, le widget peut ne pas exister, ce qui entraîne l’erreur.

final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

void submit() {
  _formKey.currentState!.validate(); // Erreur si currentState est null
}

Solution

Vérifiez si currentState n’est pas null :

void submit() {
  if (_formKey.currentState != null) {
    _formKey.currentState!.validate();
  }
}

Avatar de Pierre Courtois