I am having Late initialization error
. I am facing this issue from long time and I tried all possible ways to sort it out but, I failed can anyone help?
==============================
database_helper.dart
==============================
import 'Note.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
class DatabaseHelper {
static late DatabaseHelper _databaseHelper; //Singleton
static late Database _database; // Singleton
String noteTable = 'note_table';
String colId = 'id';
String colTitle = 'title';
String colDescription = 'description';
String colPriority = 'priority';
String colDate = 'date';
DatabaseHelper._createInstance();
factory DatabaseHelper() {
if (DatabaseHelper == null) {
_databaseHelper = DatabaseHelper._createInstance();
}
return _databaseHelper;
}
// custom getter
Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Future<Database> initializeDatabase() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'note.db';
var notesDatabase = await openDatabase(
path,
version: 1,
onCreate: _createDB,
);
return notesDatabase;
}
void _createDB(Database db, int newVersion) async {
await db.execute(
'CREATE TABLE $noteTable($colId INTEGER PRIMARY KEY AUTOINCREMENT,$colTitle TEXT,$colDescription TEXT, $colPriority INTEGER,$colDate TEXT)');
}
Future<List<Map<String, dynamic>>> getNoteMapList() async {
Database db = await this.database;
// regular MySQL query optional
// var result =
// await db.rawQuery('SELECT * from $noteTable order by $colPriority ASC');
var result = await db.query(noteTable, orderBy: '$colPriority ASC');
return result;
}
Future<int> insertNote(Note note) async {
Database db = await this.database;
var result = await db.insert(noteTable, note.toMap());
return result;
}
Future<int> updateNote(Note note) async {
Database db = await this.database;
var result = await db.update(noteTable, note.toMap(),
where: '$colId=?', whereArgs: [note.id]);
return result;
}
Future<int> deleteNote(int id) async {
Database db = await this.database;
var result = await db.rawDelete('DELETE FROM $noteTable where $colId=$id');
return result;
}
Future<int?> getCount() async {
Database db = await this.database;
List<Map<String, dynamic>> x =
await db.rawQuery('SELECT COUNT (*) from $noteTable');
int? result = Sqflite.firstIntValue(x);
return result;
}
Future<List<Note>> getNoteList() async {
var noteMapList = await getNoteMapList();
int count = noteMapList.length;
List<Note> noteList = <Note>[];
for (var i = 0; i < count; i++) {
noteList.add(Note.fromMapObject(noteMapList[i]));
}
return noteList;
}
}
Following is note_detail.dart which is using database helper capabilities. I have created some methods and getters which is using database. it is also giving an error while I haven’t use "return" in WillPopScope().
======================
note_detail.dart
======================
import 'package:flutter/material.dart';
import '../Note.dart';
import '../database_helper.dart';
import 'package:intl/intl.dart';
class NoteDetail extends StatefulWidget {
final String appBarTitle;
final Note note;
NoteDetail(this.note, this.appBarTitle);
@override
State<StatefulWidget> createState() {
return NoteDetailState(this.note, this.appBarTitle);
}
}
class NoteDetailState extends State<NoteDetail> {
static var _priorities = ['High', 'Low'];
DatabaseHelper helper = DatabaseHelper();
String appBarTitle;
Note note;
NoteDetailState(this.note, this.appBarTitle);
TextEditingController titleController = TextEditingController();
TextEditingController descriptionController = TextEditingController();
@override
Widget build(BuildContext context) {
TextStyle? textStyle = Theme.of(context).textTheme.titleMedium;
titleController.text = note.title;
descriptionController.text = note.description!;
return WillPopScope(
onWillPop: () async {
bool? result = await movetoLastScreen();
result ??= false;
return result;
},
child: Scaffold(
backgroundColor: Colors.cyanAccent,
appBar: AppBar(
title: Text(appBarTitle),
backgroundColor: Colors.pink,
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
movetoLastScreen();
},
),
),
body: Padding(
padding: EdgeInsets.all(10.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: ListView(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 15.0, bottom: 5.0),
//dropdown menu
child: new ListTile(
leading: const Icon(Icons.low_priority),
title: DropdownButton(
items: _priorities.map((String dropDownStringItem) {
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: Text(dropDownStringItem,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.red)),
);
}).toList(),
value: getPriorityAsString(note.priority),
onChanged: (valueSelectedByUser) {
setState(() {
updatePriorityAsInt(valueSelectedByUser!);
});
}),
),
),
// Second Element
Padding(
padding: EdgeInsets.only(top: 15.0, bottom: 15.0, left: 15.0),
child: TextField(
controller: titleController,
style: textStyle,
onChanged: (value) {
updateTitle();
},
decoration: InputDecoration(
labelText: 'Title',
labelStyle: textStyle,
icon: Icon(Icons.title),
),
),
),
// Third Element
Padding(
padding: EdgeInsets.only(top: 15.0, bottom: 15.0, left: 15.0),
child: TextField(
controller: descriptionController,
style: textStyle,
onChanged: (value) {
updateDescription();
},
decoration: InputDecoration(
labelText: 'Details',
icon: Icon(Icons.details),
),
),
),
// Fourth Element
Padding(
padding: EdgeInsets.all(15.0),
child: Row(
children: <Widget>[
Expanded(
child: ElevatedButton(
child: Text(
'Save',
textScaleFactor: 1.5,
style: TextStyle(
color: Colors.white,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
padding: const EdgeInsets.all(8.0),
),
onPressed: () {
setState(() {
debugPrint("Save button clicked");
_save();
});
},
),
),
Container(
width: 5.0,
),
Expanded(
child: ElevatedButton(
child: Text(
'Delete',
textScaleFactor: 1.5,
style: TextStyle(
color: Colors.white,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
padding: const EdgeInsets.all(8.0),
),
onPressed: () {
setState(() {
_delete();
});
},
),
),
],
),
),
],
),
),
),
),
);
}
void updateTitle() {
note.title = titleController.text;
}
void updateDescription() {
note.description = descriptionController.text;
}
void _save() async {
movetoLastScreen();
}
void _delete() async {
movetoLastScreen();
if (note.id == null) {
_showAlertDialog('Status', 'First add a note');
return;
}
int? result = await helper.deleteNote(note.id);
if (result != 0) {
_showAlertDialog('Status', 'Note deleted Successfully');
} else {
_showAlertDialog('Status', 'Error');
}
}
// convert to int to save into database
void updatePriorityAsInt(String value) {
switch (value) {
case 'High':
note.priority = 1;
break;
case 'Low':
note.priority = 2;
break;
}
}
// convert int to String to show user
String getPriorityAsString(int value) {
late String priority;
switch (value) {
case 1:
priority = _priorities[0];
break;
case 2:
priority = _priorities[1];
break;
}
return priority;
}
movetoLastScreen() async {
Navigator.pop(context, true);
note.date = DateFormat.yMMMd().format(DateTime.now());
int? result;
if (note.id != null) {
result = await helper.updateNote(note);
} else {
result = await helper.insertNote(note);
}
if (result != 0) {
_showAlertDialog('Status', 'Note Save Successfully');
} else {
_showAlertDialog('Status', 'Problem saving Note');
}
}
void _showAlertDialog(String title, String message) {
AlertDialog alertDialog = AlertDialog(
title: Text(title),
content: Text(message),
);
showDialog(context: context, builder: (_) => alertDialog);
}
}
I have tried every possible whether to check Null
or async
issue but nothing worked.
2
Answers
You need to make datatype nullable to do null check.
Find more about null-safety.
Change these from
to