Teniendo problemas con la seguridad nula de Flutter, el objeto de la base de datos se niega a inicializarse.
He estado intentando implementar una aplicación simple de lista de tareas sin proveedores (por el bien del curso) para avanzar en el curso al ritmo que el instructor pretendía. Pero no puedo encontrar una solución para este pequeño problema… en el siguiente código, la variable “database” no quiere inicializarse en absoluto. El método “getData()” que se supone que recupera los datos (consulta) no inicializa la variable “database” incluso si lo llamo en “createDatabase()” en “initState()”. Sigue dando los siguientes errores:
” I/flutter ( 5171): error LateInitializationError: El campo ‘database’ no ha sido inicializado. durante la apertura, cierre…
E/flutter ( 5171): [ERROR:flutter/lib/ui/uidartstate.cc(209)] Excepción no controlada: LateInitializationError: El campo ‘database’ no ha sido inicializado.
”
“` import ‘package:flutter/material.dart’;
import 'package:intl/intl.dart';
import 'package:sqflite/sqflite.dart';
import 'package:to<em>do</em>app/modules/todo<em>app/archived/archived</em>screen.dart';
import 'package:to<em>do</em>app/modules/todo<em>app/done/done</em>screen.dart';
import 'package:to<em>do</em>app/modules/todo<em>app/tasks/tasks</em>screen.dart';
class HomeLayout extends StatefulWidget {
const HomeLayout({ Key? key }) : super(key: key);
@override
State<homelayout> createState() => _HomeLayoutState();
}
class _HomeLayoutState extends State<homelayout> {
int currentIndex = 0;
List<string> titles = [
'Tareas',
'Tareas Completadas',
'Tareas Archivadas',
];
List<map> tasks = [];
late Database database;
var scaffoldKey = GlobalKey<scaffoldstate>();
bool isOpen = false;
IconData fabIcon = Icons.edit;
var titleController = TextEditingController();
var dateController = TextEditingController();
var timeController = TextEditingController();
var formKey = GlobalKey<formstate>();
@override
void initState() {
super.initState();
createDatabase();
}
@override
Widget build(BuildContext context) {
List <widget> screens = [
NewTasksScreen(),
DoneTasksScreen(),
ArchivedTasksScreen()
];
return Scaffold(
key: scaffoldKey,
appBar: AppBar(
title: Text(titles[currentIndex]),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
if(isOpen == false){
isOpen = true;
setState(() {
fabIcon = Icons.add;
});
scaffoldKey.currentState!.showBottomSheet(
(context) => SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20),
child: Form(
key: formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
validator: (value){
if(value!.isEmpty){
return 'el titulo no debe estar vacío';
}
},
controller: titleController,
decoration: InputDecoration(
labelText: 'Título',
prefixIcon: Icon(
Icons.title
),
),
),
SizedBox(height: 10),
TextFormField(
onTap: (){
showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2025)
).then((value) {
dateController.text = DateFormat.yMMMMd().format(value!);
});
},
validator: (value){
if(value!.isEmpty){
return 'la fecha no debe estar vacía';
}
},
controller: dateController,
decoration: InputDecoration(
labelText: 'Fecha',
prefixIcon: Icon(
Icons.date_range
),
),
),
SizedBox(height: 10),
TextFormField(
onTap: (){
showTimePicker(
context: context,
initialTime: TimeOfDay.now()
).then((value) {
timeController.text = value!.format(context);
});
},
validator: (value){
if(value!.isEmpty){
return 'la hora no debe estar vacía';
}
},
controller: timeController,
decoration: InputDecoration(
labelText: 'Hora',
prefixIcon: Icon(
Icons.timer
),
),
),
],
),
),
),
),
).closed.then(
(value) {
isOpen = false;
}
);
} else {
if (formKey.currentState!.validate()) {
insertIntoDatabase(
title: titleController.text,
date: dateController.text,
time: timeController.text
).then((value) {
Navigator.pop(context);
isOpen = false;
setState(() {
fabIcon = Icons.edit;
});
});
}
<pre><code> }
},
child: Icon(
fabIcon
),
</code></pre>
),
bottomNavigationBar: BottomNavigationBar(
elevation: 20,
type: BottomNavigationBarType.fixed,
currentIndex: currentIndex,
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.task_alt
),
label: 'nuevas tareas'
),
BottomNavigationBarItem(
icon: Icon(
Icons.done
),
label: 'tareas completadas'
),
BottomNavigationBarItem(
icon: Icon(
Icons.archive_outlined
),
label: 'tareas archivadas'
)
],
onTap: (index){
setState(() {
currentIndex = index;
});
},
),
body: screens[currentIndex],
);
}
Future getName() async {
return 'Ahmad Ali';
}
void createDatabase() async {
database = await openDatabase(
'todo.db',
version: 1,
onCreate: (database, version) {
print('databse creado');
database.execute(
'CREATE TABLE tasks(id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, date TEXT, time TEXT, status TEXT)'
).then(
(value) {
print('tabla creada');
}
).catchError(
(error){
print('error creando tabla ${error.toString()}');
}
);
},
onOpen: (databse) async {
print('base de datos abierta');
await getData(database).then((value) {
tasks = value;
print(tasks);
});
}
);
}
Future insertIntoDatabase({
required String title,
required String date,
required String time
}
) async {
return await database.transaction(
(txn) {
return txn.rawInsert(
'INSERT INTO tasks (title, date, time, status) VALUES ("$title", "$date", "$timeController", "new")'
).then(
(value) {
print('$value insertado correctamente');
}
).catchError(
(error){
print('Error al insertar en la tabla ${error.toString()}');
}
);
}
);
}
Future<><map>> getData(Database database) async {
return await database.rawQuery('SELECT * FROM tasks');
}
} “`
davy.ai
El problema en el código es que la variable
database
se declara utilizando la palabra clavelate
, lo que significa que se inicializará en una etapa posterior. Sin embargo, no se inicializa antes de ser utilizada en el métodogetData()
, lo que resulta en el errorLateInitializationError
.Para solucionar este problema, puede intentar inicializar la variable
database
antes de llamar al métodogetData()
. Una forma de hacerlo es llamando al métodoopenDatabase()
en el métodoinitState()
y asignando el resultado a la variabledatabase
.Por ejemplo:
Al inicializar la variable
database
en el métodoinitState()
, debería inicializarse antes de ser utilizada en el métodogetData()
, y el errorLateInitializationError
debería solucionarse.