I've got stuck with the FutureBuilder showing data from sqflite db.
I have a list of categories which is handled by FutureBuilder.
The problem is at the first application run I can see the circular indicator for one second and then it showing an empty list.
When switching to another window and then coming back to this view, it working normal, i.e showing the data which I'm putting in the database during initialization.
When running application 1st time, I creating DB in sqflite an preloading on record to the table:
class DBProvider {
DBProvider._();
static final DBProvider db = DBProvider._();
static Database _database;
Future<Database> get database async {
if (_database == null) {
return await initDB();
}
return _database;
}
Future<Database> initDB() async {
print('*** Initializing Database ***');
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, 'ToDoBuddy.db');
//print('*** Database path now is: $path ***');
return await openDatabase(path, version: 1, onOpen: (db) {},
onCreate: (Database db, int version) async {
await db.execute("CREATE TABLE CATEGORIES("
"id INTEGER PRIMARY KEY,"
"categoryName TEXT,"
"categoryColor INTEGER,"
"categoryIcon INTEGER"
")");
await db.execute("CREATE TABLE TASKS("
"id INTEGER PRIMARY KEY,"
"taskName TEXT,"
"taskDate INTEGER,"
"isCompleted INTEGER,"
"categoryID INTEGER"
")");
print('*** Executing preloadCategories ***');
Category newCategory = Category();
newCategory.categoryName = 'Default';
newCategory.categoryColor = 0;
newCategory.categoryIcon = 0;
addCategoryToDatabase(newCategory);
});
}
Then I'm fetching the data from DB to show in my Future builder:
Future<List<Category>> getAllCategories() async {
print('*** Executing getAllCategories in db helper');
final db = await database;
//var result = await db.rawQuery('SELECT * FROM CATEGORIES ORDER BY id ASC');
var result = await db.query('CATEGORIES',
columns: ['id', 'categoryName', 'categoryColor', 'categoryIcon']);
List<Category> list = result.isNotEmpty
? result.map((e) => Category.fromMap(e)).toList()
: [];
return list;
}
My Category model:
class Category {
int id;
String categoryName;
int categoryColor;
int categoryIcon;
int numberOfTasks;
Category({
this.id,
this.categoryName,
this.categoryColor,
this.categoryIcon,
this.numberOfTasks,
});
factory Category.fromMap(Map<String, dynamic> map) => Category(
id: map['id'],
categoryName: map['categoryName'],
categoryColor: map['categoryColor'],
categoryIcon: map['categoryIcon'],
);
Map<String, dynamic> toMap() => {
'id': id,
'categoryName': categoryName,
'categoryColor': categoryColor,
'categoryIcon': categoryIcon,
//'numberOfTasks': numberOfTasks,
};
}
In UI i'he created a Future builder for Categories objects:
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: MainDrawer(),
appBar: fullAppbar(context),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 10, top: 15, bottom: 0),
alignment: Alignment.bottomLeft,
child: Text(
'Categories',
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: CustomColors.TextSubHeader,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0, left: 16, right: 16),
child: FutureBuilder<List<Category>>(
future: DBProvider.db.getAllCategories(),
builder: (BuildContext context,
AsyncSnapshot<List<Category>> snapshot) {
if (snapshot.hasData) {
return GridView.builder(
physics: ScrollPhysics(),
shrinkWrap: true,
itemCount: snapshot.data.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 4,
mainAxisSpacing: 4,
),
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 8,
child: InkResponse(
onTap: () {
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 80,
height: 80,
child: Image.asset(
IconUtils.assetPath(
snapshot.data[index].categoryIcon),
),
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(50.0),
),
),
),
SizedBox(
height: 5,
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircleAvatar(
backgroundColor: Color(ColorUtils
.colorMap[
snapshot.data[index].categoryColor]),
radius: 8,
),
SizedBox(
width: 8,
),
Text(
'${snapshot.data[index].categoryName}',
maxLines: 2,
style: TextStyle(
fontSize: 18,
color: CustomColors.TextHeaderGrey,
fontWeight: FontWeight.w600,
),
),
],
),
SizedBox(
height: 8,
),
Text(
snapshot.data[index].numberOfTasks != null
? '${snapshot.data[index].numberOfTasks} Tasks'
: '0 Tasks',
style: TextStyle(
fontSize: 16,
color: CustomColors.TextSubHeaderGrey,
),
),
],
),
),
);
},
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
),
],
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: customFab(context),
bottomNavigationBar:
BottomNavigationBarApp(context, bottomNavigationBarIndex),
);
}
}