Flutter - LateError (LateInitializationError: Field '_items@68190616' has not been initialized.)

Flutter - LateError (LateInitializationError: Field '_items@68190616' has not been initialized.)

我是 Flutter 的新手,目前正在尝试使用数据库中的一些数据显示在下拉 select 菜单中(使用 mysql1 and select_form_field packages)。 SelectFormField 需要传递一个 List<Map<String, dynamic>> 作为其 items: 参数。每当我尝试 运行 我的代码时,我都会收到异常 LateError (LateInitializationError: Field '_items@68190616' has not been initialized.).

环顾四周后,似乎在 initState() 中初始化我的项目列表应该可以解决问题,但我无法让它工作。下面是我的main.dart.

class MyCustomFormState extends State<MyCustomForm> {
  ...

  late List<Map<String, dynamic>> _items;

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

  _getData() async {
    _items = await getData();
  }

  Widget build(BuildContext context) {

    return Form(
      key: _formKey,
      child: Column( 
        children: <Widget>[
          Container(
            child: SelectFormField(
            controller: nameController,
            hintText: "...",
            items: _items,
            ...
}

这是我的 database.dart 文件,它能够以我需要的 List<Map<String, dynamic>> 格式获取和格式化数据:

getData() async {
  List<Map<String, dynamic>> items = <Map<String, dynamic>>[];
  dynamic conn = await connect('database');

  var results = await conn.query('select * from data');

  for (var row in results) {
    items.add({'value': row[0], 'label': row[1]});
  }

  await conn.close();

  return items;
}

非常感谢任何帮助。谢谢!

尝试在 initState() 上创建空地图,然后再使用它。因为当进入构建阶段时,它会访问引发错误的空映射。

  @override
  void initState() {
    _items = <Map<String,dynamic>>[] // Empty one
    _items = _getData(); // Or you can assign it immediately 
    super.initState();
  }

编辑:尝试将 Initiate 与 initState 分开,因为你向我展示的错误是必须是 Future as await 并将其转换为所需的类型(在本例中为 List<Map<String, dynamic>>

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

void _getDataInit() async {
  _items = await _getData() as List<Map<String, dynamic>>;
}

Edit2:经过调查,发现 Future 的实现是错误的。我添加了 FutureBuilder 并删除了 initState_items 变量来解决这个问题,这里是工作代码(只需将其粘贴为 form.dart):

import 'database.dart';

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:select_form_field/select_form_field.dart';
import 'package:date_time_picker/date_time_picker.dart';

class MyCustomForm extends StatefulWidget {
  const MyCustomForm({Key? key}) : super(key: key);

  @override
  MyCustomFormState createState() {
    return MyCustomFormState();
  }
}

class MyCustomFormState extends State<MyCustomForm> {
  final _formKey = GlobalKey<FormState>();

  var nameController = TextEditingController();
  var dateController = TextEditingController();
  var courseController = TextEditingController();
  var scoreController = TextEditingController();

  final dateFormat = DateFormat('dd-MM-yyyy');

  final database = Database();

  @override
  void dispose() {
    nameController.dispose();
    dateController.dispose();
    courseController.dispose();
    scoreController.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    bool shouldDisplay = false;

    return Form(
      key: _formKey,
      child: FutureBuilder<List<Map<String, dynamic>>>(
          future: database.getBandits(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return const Center(
                child: CircularProgressIndicator(),
              );
            } else {
              if (snapshot.hasError) {
                return ErrorWidget(Exception(
                    'Error occured when fetching data from database'));
              } else if (!snapshot.hasData) {
                return const Center(child: Text('Bandit is empty!'));
              } else {
                return Column(
                  mainAxisSize: MainAxisSize.min,
                  children: <Widget>[
                    Container(
                      padding: const EdgeInsets.symmetric(
                          vertical: 10.0, horizontal: 30.0),
                      child: SelectFormField(
                        controller: nameController,
                        hintText: "...",
                        items: snapshot.data,
                        validator: (value) {
                          if (value == null || value.isEmpty) {
                            return "Hvem er du?";
                          }
                          return null;
                        },
                        decoration: const InputDecoration(
                            border: OutlineInputBorder(),
                            labelText: 'Bandit',
                            prefixIcon: Align(
                              widthFactor: 1.0,
                              heightFactor: 1.0,
                              child: Icon(Icons.person),
                            ),
                            suffixIcon: Align(
                              widthFactor: 1.0,
                              heightFactor: 1.0,
                              child: Icon(Icons.arrow_drop_down),
                            )),
                      ),
                    ),
                    Container(
                      padding: const EdgeInsets.symmetric(
                          vertical: 10.0, horizontal: 30.0),
                      child: DateTimePicker(
                        controller: dateController,
                        validator: (value) {
                          if (value == null || value.isEmpty) {
                            setState(() {
                              dateController.text =
                                  dateFormat.format(DateTime.now()).toString();
                            });
                          }
                          return null;
                        },
                        type: DateTimePickerType.date,
                        dateMask: 'dd-MM-yyyy',
                        firstDate: DateTime(2020),
                        lastDate: DateTime(2050),
                        dateLabelText: 'Dato',
                        decoration: const InputDecoration(
                            border: OutlineInputBorder(),
                            labelText: 'Dato',
                            prefixIcon: Align(
                              widthFactor: 1.0,
                              heightFactor: 1.0,
                              child: Icon(Icons.date_range),
                            )),
                      ),
                    ),
                    Container(
                      padding: const EdgeInsets.symmetric(
                          vertical: 10.0, horizontal: 30.0),
                      child: TextFormField(
                        controller: courseController,
                        validator: (value) {
                          if (value == null || value.isEmpty) {
                            setState(() {
                              courseController.text = "HJGK";
                            });
                          }
                          return null;
                        },
                        decoration: const InputDecoration(
                            border: OutlineInputBorder(),
                            labelText: 'Bane',
                            prefixIcon: Align(
                              widthFactor: 1.0,
                              heightFactor: 1.0,
                              child: Icon(Icons.golf_course),
                            )),
                      ),
                    ),
                    Container(
                        padding: const EdgeInsets.symmetric(
                            vertical: 10.0, horizontal: 30.0),
                        child: TextFormField(
                          controller: scoreController,
                          validator: (value) {
                            if (value == null || value.isEmpty) {
                              return "Indtast score";
                            }
                            return null;
                          },
                          keyboardType: TextInputType.number,
                          decoration: const InputDecoration(
                            border: OutlineInputBorder(),
                            labelText: 'Score',
                            prefixIcon: Align(
                                widthFactor: 1.0,
                                heightFactor: 1.0,
                                child: Icon(Icons.sports_score)),
                          ),
                        )),
                    ElevatedButton(
                        onPressed: () {
                          if (_formKey.currentState!.validate()) {
                            _formKey.currentState!.save();
                            shouldDisplay = !shouldDisplay;
                          }
                          shouldDisplay
                              ? showDialog(
                                  context: context,
                                  builder: (context) {
                                    return AlertDialog(
                                      title: const Text("Score registreret"),
                                      content: SingleChildScrollView(
                                        child: ListBody(
                                          children: <Widget>[
                                            Padding(
                                              padding:
                                                  const EdgeInsets.symmetric(
                                                      vertical: 10),
                                              child: Text(
                                                  "Spiller: ${nameController.text}"),
                                            ),
                                            Padding(
                                              padding:
                                                  const EdgeInsets.symmetric(
                                                      vertical: 10),
                                              child: Text(
                                                  "Dato: ${dateController.text}"),
                                            ),
                                            Padding(
                                              padding:
                                                  const EdgeInsets.symmetric(
                                                      vertical: 10),
                                              child: Text(
                                                  "Bane: ${courseController.text}"),
                                            ),
                                            Padding(
                                              padding:
                                                  const EdgeInsets.symmetric(
                                                      vertical: 10),
                                              child: Text(
                                                  "Score: ${scoreController.text}"),
                                            ),
                                          ],
                                        ),
                                      ),
                                      actions: <Widget>[
                                        TextButton(
                                          child: const Text('OK'),
                                          onPressed: () {
                                            Navigator.of(context).pop();
                                          },
                                        ),
                                      ],
                                    );
                                  },
                                )
                              : null;
                        },
                        child: const Text("Submit")),
                  ],
                );
              }
            }
          }),
    );
  }
}