I have a screen that is reading data from a database table (sqllite) but the data is not been display in my listview. it looks like when i read the data the screen already display the gui and my array is not populated with data by the time the listview access the array. below is my code
import 'package:finsec/model/cardview_list_item.dart';
import 'package:flutter/material.dart';
import 'package:finsec/utils/strings.dart';
import 'package:finsec/utils/colors.dart';
import 'package:finsec/widget/circle_icon.dart';
import 'package:finsec/data/db_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:finsec/utils/queries.dart';
class CardviewListItemData extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return CardviewListItemDataState();
}
}
class CardviewListItemDataState extends State<CardviewListItemData> {
DBProvider db = new DBProvider();
List<String> amountList;
List<CardviewListItem> listItems = List<CardviewListItem>();
int count = 0;
@override
Widget build(BuildContext context) {
if (amountList == null) {
amountList = List<String>();
updateListView();
listItems = summaryList();
}
return ListView.builder(
itemCount: listItems.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(listItems[index].icon, color: listItems[index].iconColor),
title: Align(
child: new Text(listItems[index].title,style: TextStyle(fontSize: 16)),
alignment: Alignment(-1.4, 0),
),
trailing: new Text(listItems[index].amount, style: TextStyle(fontSize: 16),),
//onTap: () => onTapped(context, listItems[index].title),
);
},
);
}
List<CardviewListItem> summaryList() {
List<CardviewListItem> summaryListItems = List<CardviewListItem>();
CardviewListItem income = new CardviewListItem(
title: totalIncome,
amount: amountList[0],
icon: Icons.attach_money,
iconColor: green
);
summaryListItems.add(income);
return summaryListItems;
}
void updateListView() {
final Future<Database> dbFuture = db.initializeDatabase();
dbFuture.then((database) {
Future<List<String>> incomeListFuture = db.getDataList(test);
incomeListFuture.then((amountList) {
setState(() {
this.amountList = amountList;
this.count = this.amountList.length;
});
});
});
}
}
my database code is
import 'dart:io';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:finsec/model/transaction_content.dart';
import 'package:finsec/utils/tables.dart';
import 'package:finsec/model/income/income_dao.dart';
import 'package:finsec/model/income/income.dart';
import 'package:finsec/model/list_item.dart';
import 'package:finsec/model/dao.dart';
import 'package:finsec/model/cardview_list_item.dart';
import 'package:finsec/utils/strings.dart';
import 'package:finsec/utils/colors.dart';
import 'package:finsec/widget/circle_icon.dart';
import 'package:finsec/data/db_provider.dart';
class DBProvider {
static DBProvider db; // Singleton DBProvider
static Database _database; // Singleton Database
DBProvider._createInstance(); // Named constructor to create instance of DBProvider
factory DBProvider() {
if (db == null) {
db = DBProvider._createInstance(); // This is executed only once, singleton object
}
return db;
}
Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Future<Database> initializeDatabase() async {
// Get the directory path for both Android and iOS to store database.
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'finsec.db';
// Open/create the database at a given path
var finsecDatabase = await openDatabase(path, version: 4, onCreate: _createDb, onUpgrade: _onUpgrade);
return finsecDatabase;
}
void _createDb(Database db, int newVersion) async {
// await db.execute('drop table income');
print('CREATE THE TABLE2');
await db.execute(incomeTable);
//await db.execute("CREATE TABLE User(id INTEGER PRIMARY KEY, firstname TEXT, lastname TEXT, dob TEXT)");
}
// UPGRADE DATABASE TABLES
void _onUpgrade(Database db, int oldVersion, int newVersion) async {
if (oldVersion < newVersion) {
await db.execute('drop table income');
await db.execute(incomeTable);
}
}
// Fetch Operation: Get all row objects from database
Future<List<Map<String, dynamic>>> getTransactions(String tableName) async {
Database db = await this.database;
//var result = await db.rawQuery(tableName);
var result = await db.query(tableName);
result.forEach((row) => print(row));
// var res = await db.insert('note', transactionType.toMap());
return result;
}
// Fetch Operation: Get all row objects from database
Future<List<Map<String, dynamic>>> getTransactionsQuery(String query) async {
Database db = await this.database;
var result = await db.rawQuery(query);
return result;
}
// Insert Operation: Insert a transaction object to database
Future<int> insertTransaction(String sqlQuery) async {
Database db = await this.database;
//var dao = new IncomeDao();
var result = await db.rawInsert(sqlQuery); //insert(noteTable, note.toMap());
//var result = await db.insert('noteTable', transaction);
return result;
}
// Update Operation: Update a Note object and save it to database
Future<int> updateTransaction(Map transaction) async {
var db = await this.database;
//var result = await db.rawUpdate(sql);// update(noteTable, note.toMap(), where: '$colId = ?', whereArgs: [note.id]);
var result = await db.update('noteTable', transaction);
return result;
}
// Delete Operation: Delete a transaction object from database
Future<int> deleteTransaction(int id) async {
var db = await this.database;
int result = await db.rawDelete('DELETE FROM noteTable WHERE ');
return result;
}
// Get number of Note objects in database
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;
}
// Get the 'Map List' [ List<Map> ] and convert it to 'Note List' [ List<Note> ]
Future<List<Income>> getIncomeList(String tableName) async {
var incomeMapList = await getTransactions(tableName); // Get 'Map List' from database
int count = incomeMapList.length; // Count the number of map entries in db table
List<Income> incomeList = List<Income>();
// For loop to create a 'Income List' from a 'Map List'
for (int i = 0; i < count; i++) {
incomeList.add(Income.fromMap(incomeMapList[i]));
}
return incomeList;
}
// Get the 'Map List' [ List<Map> ] and convert it to 'Note List' [ List<Note> ]
Future<List<String>> getDataList(String query) async {
var dataMapList = await getTransactionsQuery(query); // Get 'Map List' from database
int count = dataMapList.length; // Count the number of map entries in db table
List<String> dataList = List<String>();
Map<String, dynamic> queryData;
for (int i = 0; i < count; i++) {
queryData = dataMapList[i];
dataList.add(queryData["amount"]);
}
return dataList;
}
}
i think the problem is in the following portion of the code
if (amountList == null) {
amountList = List<String>();
updateListView();
listItems = summaryList();
}
updateListView() is getting called but it looks like the code continue executing to the next line even if updateListView didnt finish executing. when i called amountList[0] in summaryList(), i get the following error
RangeError (index): Invalid value: Valid value range is empty: 0
I/flutter ( 3640):
I/flutter ( 3640): User-created ancestor of the error-causing widget was:
I/flutter ( 3640): Column file:///C:/Users/rodrigue33/Documents/APP/finsec/lib/widget/cardview_widget.dart:45:22
I/flutter ( 3640):
I/flutter ( 3640): When the exception was thrown, this was the stack:
I/flutter ( 3640): #0 List.[] (dart:core-patch/growable_array.dart:145:60)
I/flutter ( 3640): #1 CardviewListItemDataState.summaryList (package:finsec/data/cardview_list_item.dart:114:27)
I/flutter ( 3640): #2 CardviewListItemDataState.build (package:finsec/data/cardview_list_item.dart:80:19)
I/flutter ( 3640): #3 StatefulElement.build (package:flutter/src/widgets/framework.dart:4040:27)
this is my assumption of what is happening. do anyone agree with me? how can i solve this issue of waiting for database to return data before displaying the data in the listview? thanks in advance