我有一个正在从数据库表(sqllite)读取数据的屏幕,但是该数据未显示在我的列表视图中。看起来当我读取数据时,屏幕已经显示gui了,并且当listview访问数组时,我的数组还没有填充数据。 下面是我的代码
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;
});
});
});
}
}
我的数据库代码是
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;
}
}
我认为问题出在代码的以下部分
if (amountList == null) {
amountList = List<String>();
updateListView();
listItems = summaryList();
}
updateListView()被调用,但是即使updateListView没有完成执行,代码仍继续执行到下一行。当我在summaryList()中调用amountList [0]时,出现以下错误
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)
这是我对正在发生的事情的假设。有人同意我吗?我如何解决在列表视图中显示数据之前等待数据库返回数据的问题?预先感谢
答案 0 :(得分:1)
问题是您正在调用setState方法并更新其“ amountList”,因为setState重新加载页面时它并没有完全执行“ listItems = summaryList();”。
也许一个快速的解决方法是创建一个布尔检查并将其保留为false,在执行setState时将其设置为true,并在您的构建器方法中执行以下操作:
if (amountList == null) {
amountList = List<String>();
updateListView();
}
if(check){
listItems = summaryList();
}
注意:我建议在您的方法中使用async和await,而不要在将来使用。
void updateListView() async{
final Database db = await db.initializeDatabase();
List<String> incomeList = await db.getDataList(test);
setState(() {
this.amountList = amountList;
this.count = this.amountList.length;
this.check = true;
});
}
希望我能帮助您!