繁体   English   中英

Flutter:未处理的异常:Null 检查运算符用于 null 值

[英]Flutter: Unhandled Exception: Null check operator used on a null value

我正在 flutter App 中使用 SQFLite 数据库进行练习。 我想创建一个数据库,用户可以在其中添加朋友的姓名和手机号码。

用户界面输出

添加此信息后,该信息列表将显示在提交按钮 [ 我使用listview.builder() ] 下。

一切都很好。 数据正在添加到数据库。 (我也手动检查了.db文件)。 但是当我刷新列表时,它会向我显示这样的错误 -

flutter: Done Fetch
[VERBOSE-2:ui_dart_state.cc(199)] Unhandled Exception: Null check operator used on a null value
#0      QueryResultSet.columnIndex (package:sqflite_common/src/collection_utils.dart:114:32)
#1      QueryRow.[] (package:sqflite_common/src/collection_utils.dart:135:40)
#2      new Contact.fromMap (package:sample/model/contact.dart:25:15)
#3      DatabaseHelper.fetchContacts.<anonymous closure> (package:sample/utils/database_helper.dart:63:39)
#4      MappedListIterable.elementAt (dart:_internal/iterable.dart:412:31)
#5      ListIterator.moveNext (dart:_internal/iterable.dart:341:26)
#6      new _GrowableList._ofEfficientLengthIterable (dart:core-patch/growable_array.dart:188:27)
#7      new _GrowableList.of (dart:core-patch/growable_array.dart:150:28)
#8      new List.of (dart:core-patch/array_patch.dart:50:28)
#9      ListIterable.toList (dart:_internal/iterable.dart:212:44)
#10     DatabaseHelper.fetchContacts (package:sample/utils/database_helper.dart:63:51)
<asynchronous suspension>

数据获取 function 也运行良好。 (控制台向我显示print("Done Fetch");的输出)。 我认为刷新function有问题。

请有人帮助我。 问题出在哪里,我该如何解决?

用户界面 =>

import 'package:flutter/material.dart';
.....

class FlutterLocalDatabase extends StatefulWidget {
  @override
  _FlutterLocalDatabaseState createState() => _FlutterLocalDatabaseState();
}

class _FlutterLocalDatabaseState extends State<FlutterLocalDatabase> {
 ....
  Contact _contact = Contact();
  List<Contact> contactList = [];

  DatabaseHelper _dbHelper;
  @override
  void initState() {
    super.initState();
    setState(() {
      _dbHelper = DatabaseHelper.instance;
    });

    refreshContactList();
  }

  @override
  Widget build(BuildContext context) {
    double _width = MediaQuery.of(context).size.width;
    double _height = MediaQuery.of(context).size.height;
    return Scaffold(
      appBar: AppBar(
        title: Text("Flutter SQFLite Database"),
      ),
      body: GestureDetector(
        ......
        .....
                ElevatedButton(
                    onPressed: () async {
                      print("${_contact.name}, ${_contact.mobile}");
                      if (validateAndSave(_formKey)) {
                        FocusScope.of(context).requestFocus(new FocusNode());
                        if (_contact.id == null) {
                          await _dbHelper.insertContact(_contact).then((value) {
                            print(value);
                            _resetForm();
                            refreshContactList();
                          });
                        }

                        print(contactList);
                      }
                    },
                    child: Text("Submit")),
                SizedBox(
                  height: 20,
                ),
                Expanded(
                    child: Container(
                  child: ListView.builder(
                      itemCount: contactList.length,
                      itemBuilder: (buildContext, index) {
                        var contact = contactList[index];
                        return Card(
                          child: ListTile(
                            leading: Icon(
                              Icons.account_circle,
                              size: 40,
                              color: Colors.teal,
                            ),
                            title: Text(
                              contact.name,
                              style: TextStyle(
                                color: Colors.teal,
                              ),
                            ),
                            subtitle: Text(contact.mobile,
                                style: TextStyle(
                                  color: Colors.teal,
                                )),
                            trailing: Text("${contact.id}",
                                style: TextStyle(
                                  color: Colors.teal,
                                )),
                          ),
                        );
                      }),
                ))
              ],
            ),
          ),
        ),
      ),
    );
  }

  refreshContactList() async {
    List<Contact> x = await _dbHelper.fetchContacts();
    print("Done Refresh");
    setState(() {
      contactList = x;
    });
  }

  _resetForm() {
    setState(() {
      _formKey.currentState.reset();
      _ctrlName.clear();
      _ctrlMobile.clear();
      _contact.id = null;
    });
  }
}

Model Class =>

class Contact {
  static const tblContact = "contacts";
  static const colId = "id";
  static const colName = "name";
  static const colMobile = "mobile";

  Contact({
    this.id,
    this.name,
    this.mobile,
  });

  int id;
  String name;
  String mobile;

  Map<String, dynamic> toMap() {
    Map map = <String, dynamic>{colName: name, colMobile: mobile};
    if (id != null) map[colId] = id;
    return map;
  }

  Contact.fromMap(Map<String, dynamic> map) {
    id = map[colId];
    name = map[name];
    mobile = map[colMobile];
  }
}

数据库助手 Class =>

import 'dart:io';
.....
class DatabaseHelper {
  static const _databaseName = "ContactData.db";
  static const _databaseVersion = 1;

//<====== Singleton Class
  DatabaseHelper._();
  static final DatabaseHelper instance = DatabaseHelper._();

  Database _database;
  Future<Database> get database async {
    if (_database != null) {
      return _database;
    } else {
      _database = await _initDatabase();
      return _database;
    }
  }

//CREATE DATABASE
  _initDatabase() async {
    Directory dataDirectory = await getApplicationDocumentsDirectory();
    String dbPath = join(dataDirectory.path, _databaseName);
    print(dbPath);
    return await openDatabase(dbPath,
        version: _databaseVersion, onCreate: _onCreate);
  }

  //CREATE TABLE
  _onCreate(Database db, int version) async {
    db.execute(''' 
CREATE TABLE ${Contact.tblContact}(
  ${Contact.colId} INTEGER PRIMARY KEY AUTOINCREMENT,
  ${Contact.colName} STRING NOT NULL,
  ${Contact.colMobile} STRING NOT NULL
);
''');
    print("Done on Create");
  }

  //<===================  ADD DATA

  Future<int> insertContact(Contact contact) async {
    Database db = await database;
    print("Done on Insert");
    return await db.insert(Contact.tblContact, contact.toMap());
  }

  //<==================== Read Data
  Future<List<Contact>> fetchContacts() async {
    Database db = await database;
    List<Map> contacts = await db.query(Contact.tblContact);
    print("Done Fetch");
    return contacts.length == 0
        ? []
        : contacts.map((x) => Contact.fromMap(x)).toList();
  }

}

map 索引运算符可以为空
这意味着如果找不到索引,它可以返回 null 因此你应该让你的 model 属性为空

class Contact {
  ...

  int? id;
  String? name;
  String? mobile;

来自 Dart 文档:

声音 null 安全适用于 Dart 2.12 和 Flutter 2。

如果您启用 null 安全,变量不能包含 null,除非您说它们可以。

您可以通过在其类型末尾放置问号 (?) 来使变量可为空。

假设我们正在从数据库中读取“联系人”,并且我们期待一个字符串列表,每个字符串都可能是 null。 使用 null 安全性,您可以指示一个值可以接受 null 吗? 运算符,它使数据类型可以为空(默认情况下,没有变量可以包含空值)。 让我们进一步假设我们“知道”我们读取的所有名称都不会是 null。 我们可以用 . 运算符,使用循环和异常处理,我们将查看每个元素并测试此断言。 如果它被证明是错误的,那么 null 将被一个空字符串(或任何你喜欢的)替换。

// without the nullable operator (?), the next line will not compile
// The element type 'Null' can't be assigned to the list type
List<String?> contactsRead = ['Steve', null, 'Tina', 'Aaron', 'Jessica'];
print('Contacts read: $contactsRead\n');
for (int i = 0; i < contactsRead.length; i++) {
    try {
        // without the assertion operator (!) the next line will not compile
        // A value of type 'String?' can't be assigned to a variable of type 'String'
        String contact = contactsRead[i]!;

        // Item was not null, everything fine
        print('Contact ${i + 1} is valid:  $contact');
     } catch (e) {
        // Item was null, let's fix it
        print("An error occurred: e.toString() = '${e.toString()}'");
        print("Its type is: e.runtimeType = ${e.runtimeType}");
        print('Contact ${i + 1} is not valid, we will set to ""');
        print('Contact ${i + 1} is now ${contactsRead[i] = ""}an empty string');
     }
}
print('\n$contactsRead');

这是 output:

Contacts read: [Steve, null, Tina, Aaron, Jessica]

Contact 1 is valid:  Steve
An error occurred: e.toString() = 'Null check operator used on a null value'
Its type is: e.runtimeType = _CastError
Contact 2 is not valid, we will set to ""
Contact 2 is now an empty string
Contact 3 is valid:  Tina
Contact 4 is valid:  Aaron
Contact 5 is valid:  Jessica

[Steve, , Tina, Aaron, Jessica]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM