You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dart类型错误:'Null'不是'int'的子类型问题求助

问题排查:type 'Null' is not a subtype of type 'int'错误解决

错误详情

页面初始化时触发错误:type 'Null' is not a subtype of type 'int',关联错误组件为MaterialApp,栈追踪如下:

MaterialApp MaterialApp:file:///D:/Users/lebourgeois/android_studio_projects/tp1/lib/coursSQLite/main.dart:10:12
When the exception was thrown, this was the stack: 
#0      new Personne.fromMap (package:tp1/coursSQLite/Personne.dart:24:5)
#1      _PersonnePageState.initState (package:tp1/coursSQLite/PersonnePage.dart:33:36)

错误核心原因:Personne类的id字段定义为非空int类型,但初始化时传入的mapPersonne不包含id键(新创建的记录未插入数据库,id由SQLite自增生成),导致map[colonneId]返回null,无法赋值给非空int类型变量。

相关代码

Personne.dart

import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';

const String tablePersonne = 'personne';
const String colonneId = 'id';
const String colonneNom = 'nom';
const String colonnePrenom = 'prenom';
const String colonneAge = 'age';

const String databaseName = 'PersonneDB.db';
const int databaseVersion = 1;

class Personne {
  late int id;
  late String nom;
  late String prenom;
  late String age;

  Personne();

  Personne.fromMap(Map<String, dynamic> map) {
    id = map[colonneId];
    nom = map[colonneNom];
    prenom = map[colonnePrenom];
    age = map[colonneAge];
  }


  Map<String, dynamic> toMap() {
    var map = <String, dynamic>{
      colonneNom: nom,
      colonnePrenom: prenom,
      colonneAge: age
    };
    if (id != null) {
      map[colonneId] = id;
    }
    return map;
  }
}

class PersonneProvider {
  PersonneProvider._privateConstructor();
  static final PersonneProvider instance = PersonneProvider._privateConstructor();
  late Database _db;
  bool _initialized = false;

  Future<Database> get db async {
    if (!_initialized) {
      _db = await _initDatabase();
      _initialized = true;
    }
    return _db;
  }

  Future _initDatabase() async {
    try {
      Directory documentsDirectory = await getApplicationDocumentsDirectory();
      String path = join(documentsDirectory.path, databaseName);
      return await openDatabase(path, version: databaseVersion, onCreate: _open);
    } catch (e) {
      print("Erreur lors de l'initialisation de la base de données: $e");
      rethrow;
    }
  }

  Future _open(Database db, int version) async {
    await db.execute(''' 
     create table $tablePersonne ( 
     $colonneId integer primary key autoincrement, 
     $colonneNom text,
     $colonnePrenom text,
     $colonneAge text) 
     ''');
  }

  Future<int> insert(Personne personne) async {
    Database db = await instance.db;
    int id = await db.insert(tablePersonne, personne.toMap());
    return id;
  }

  Future<Personne?> getPersonne(int id) async {
    Database db = await instance.db;
    List<Map<String, dynamic>> maps = await db.query(tablePersonne,
        columns: [colonneId, colonneNom, colonnePrenom, colonneAge],
        where: '$colonneId = ?',
        whereArgs: [id]);
    if (maps.length > 0) {
      Map<String, dynamic> firstMap = maps.first;
      return Personne.fromMap({
        colonneId: firstMap[colonneId],
        colonneNom: firstMap[colonneNom],
        colonnePrenom: firstMap[colonnePrenom],
        colonneAge: firstMap[colonneAge],
      });
    }
    return null;
  }


  Future<int> delete(int id) async {
    Database db = await instance.db;
    return await db.delete(tablePersonne, where: '$colonneId = ?', whereArgs: [id]);
  }

  Future close() async => _db.close();
}

PersonnePage.dart

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'main.dart';
import 'Personne.dart';
import '../CheckboxPage.dart';

void main() => runApp(CheckboxPage());

class PersonnePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SIO',
      theme: ThemeData.light(),
      home: const PersonnePageState(title: 'Cours'),
    );
  }
}

class PersonnePageState extends StatefulWidget {
  const PersonnePageState({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _PersonnePageState createState() => _PersonnePageState();
}

class _PersonnePageState extends State<PersonnePage> {
  @override
  void initState() {
    super.initState();
    personneEnregistree = Personne.fromMap(mapPersonne);
    getInstance();
  }

  @override
  void dispose() {
    super.dispose();
    provider.close();
  }

  final Map<RadioChoix, bool> _mapTransport = {
    RadioChoix.voiture: true,
    RadioChoix.avion: false,
    RadioChoix.bateau: true,
  };

  Map<String, dynamic> mapPersonne = {
    'nom': 'DOE',
    'prenom': 'John',
    'age': '35'
  };
  late Map<String, dynamic> mapPersonneRecuperee;
  Personne personneEnregistree = Personne();
  Personne personneRecuperee = Personne();
  late PersonneProvider provider;

  Future<PersonneProvider> getInstance() async {
    provider = await PersonneProvider.instance;
    return provider;
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            const Icon(
              Icons.account_circle,
              size: 80.0,
              color: Colors.blue,
            ),
            const Text('Données soumises :'),
            Container(
              height: MediaQuery.of(context).size.height * 0.25,
              width: MediaQuery.of(context).size.width * 0.8,
              decoration: BoxDecoration(
                color: Colors.grey,
                shape: BoxShape.rectangle,
                borderRadius: BorderRadius.circular(20.0),
              ),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      const Text(
                        'Nom : ',
                        style: TextStyle(color: Colors.white),
                      ),
                      Text(
                        '${personneEnregistree.toMap()['nom']}',
                        style: const TextStyle(
                            fontSize: 30.0,
                            color: Colors.white,
                            fontWeight: FontWeight.bold),
                      ),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      const Text(
                        'Prénom : ',
                        style: TextStyle(color: Colors.white),
                      ),
                      Text(
                        '${personneEnregistree.toMap()['prenom']}',
                        style: const TextStyle(
                            fontSize: 30.0,
                            color: Colors.white,
                            fontWeight: FontWeight.bold),
                      ),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      const Text(
                        'Age : ',
                        style: TextStyle(color: Colors.white),
                      ),
                      Text(
                        '${personneEnregistree.toMap()['age']}',
                        style: const TextStyle(
                            fontSize: 30.0,
                            color: Colors.white,
                            fontWeight: FontWeight.bold),
                      ),
                    ],
                  ),
                ],
              ),
            ),
            const Text('Données récupérées :'),
            Container(
              height: MediaQuery.of(context).size.height * 0.25,
              width: MediaQuery.of(context).size.width * 0.8,
              decoration: BoxDecoration(
                color: Colors.blue,
                shape: BoxShape.rectangle,
                borderRadius: BorderRadius.circular(20.0),
              ),
              child: const Column(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        'id : ',
                        style: TextStyle(color: Colors.white),
                      ),
                      Text(
                        '123',
                        style: TextStyle(
                            fontSize: 25.0,
                            color: Colors.white,
                            fontWeight: FontWeight.bold),
                      ),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        'Nom : ',
                        style: TextStyle(color: Colors.white),
                      ),
                      Text(
                        'John Doe',
                        style: TextStyle(
                            fontSize: 25.0,
                            color: Colors.white,
                            fontWeight: FontWeight.bold),
                      ),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        'Prénom : ',
                        style: TextStyle(color: Colors.white),
                      ),
                      Text(
                        'Jane Doe',
                        style: TextStyle(
                            fontSize: 25.0,
                            color: Colors.white,
                            fontWeight: FontWeight.bold),
                      ),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        'Age : ',
                        style: TextStyle(color: Colors.white),
                      ),
                      Text(
                        '30',
                        style: TextStyle(
                            fontSize: 25.0,
                            color: Colors.white,
                            fontWeight: FontWeight.bold),
                      ),
                    ],
                  ),
                ],
              ),
            ),
            Divider(),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                ElevatedButton(
                  onPressed: enregistrer,
                  style: ElevatedButton.styleFrom(
                    foregroundColor: Colors.white, backgroundColor: Colors.green,
                  ),
                  child: Text('Enregistrer'),
                ),
                ElevatedButton(
                  onPressed: recuperer,
                  style: ElevatedButton.styleFrom(
                    foregroundColor: Colors.white, backgroundColor: Colors.green,
                  ),
                  child: Text('Lire les données'),
                ),
                ElevatedButton(
                  onPressed: supprimer,
                  style: ElevatedButton.styleFrom(
                    foregroundColor: Colors.white, backgroundColor: Colors.green,
                  ),
                  child: const Icon(
                    Icons.delete,
                    color: Colors.white,
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  Future<void> enregistrer() async {
    int id = await provider.insert(personneEnregistree);
    mapPersonneRecuperee = {'id': id};
    personneRecuperee = Personne.fromMap(mapPersonneRecuperee);
    showDialog(
        context: context,
        builder: (BuildContext context) {
          return const AlertDialog(
            title: Text('Enregistrement'),
            content: Text('Les données ont été enregistrées !'),
          );
        });
  }

  Future<void> recuperer() async {
    if (personneRecuperee.toMap()['id'] != 10) {
      personneRecuperee =
      (await provider.getPersonne(personneRecuperee.toMap()['id']))!;
      setState(() {});
    } else {
      showDialog(
          context: context,
          builder: (BuildContext context) {
            return const AlertDialog(
              title: Text('Récupération'),
              content: Text('Aucune donnée à récupérer !'),
            );
          });
    }
  }

  Future<void> supprimer() async {
    await provider.delete(personneRecuperee.toMap()['id']);
    setState(() {
      personneRecuperee = Personne();
    });
    showDialog(
        context: context,
        builder: (BuildContext context) {
          return const AlertDialog(
            title: Text('Suppression'),
            content: Text('Les données ont été supprimées !'),
          );
        });
  }
}

解决方法

方案一:将id设为可空类型

修改Personne类,允许id为null,适配未插入数据库的记录状态:

class Personne {
  int? id; // 改为可空int类型
  late String nom;
  late String prenom;
  late String age;

  Personne();

  Personne.fromMap(Map<String, dynamic> map) {
    id = map[colonneId]; // 无id时自动赋值为null,可空类型兼容
    nom = map[colonneNom];
    prenom = map[colonnePrenom];
    age = map[colonneAge];
  }

  Map<String, dynamic> toMap() {
    var map = <String, dynamic>{
      colonneNom: nom,
      colonnePrenom: prenom,
      colonneAge: age
    };
    if (id != null) { // 仅当id不为null时,才加入map
      map[colonneId] = id;
    }
    return map;
  }
}

方案二:给id设置默认值

如果不想使用可空类型,可以给id设置默认值(比如0,代表未插入数据库的记录):

class Personne {
  int id = 0; // 默认值0,区别于自增的正整数id
  late String nom;
  late String prenom;
  late String age;

  Personne();

  Personne.fromMap(Map<String, dynamic> map) {
    id = map[colonneId] ?? 0; // 无id时使用默认值0
    nom = map[colonneNom];
    prenom = map[colonnePrenom];
    age = map[colonneAge];
  }

  Map<String, dynamic> toMap() {
    var map = <String, dynamic>{
      colonneNom: nom,
      colonnePrenom: prenom,
      colonneAge: age
    };
    if (id != 0) { // 仅当id不为0时,才加入map
      map[colonneId] = id;
    }
    return map;
  }
}

额外优化

在PersonnePage的enregistrer方法中,插入数据库后返回的id可以直接赋值给personneEnregistree.id,无需重新创建personneRecuperee:

Future<void> enregistrer() async {
  int id = await provider.insert(personneEnregistree);
  personneEnregistree.id = id; // 直接赋值给原实例的id
  showDialog(
      context: context,
      builder: (BuildContext context) {
        return const AlertDialog(
          title: Text('Enregistrement'),
          content: Text('Les données ont été enregistrées !'),
        );
      });
}

内容的提问来源于stack exchange,提问作者Fabien Lebourgeois

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 17:50:54