FutureBuilder and SQFLite

493 views
Skip to first unread message

Igor Karelin

unread,
Jun 4, 2020, 6:13:54 AM6/4/20
to Flutter Development (flutter-dev)
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),
);
}
}

Suzuki Tomohiro

unread,
Jun 4, 2020, 7:25:45 AM6/4/20
to Igor Karelin, Flutter Development (flutter-dev)
You need to await “ addCategoryToDatabase(newCategory)”.

--
You received this message because you are subscribed to the Google Groups "Flutter Development (flutter-dev)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to flutter-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/flutter-dev/c3e9d379-8c49-41f1-9afa-8a4ca2c5b9ad%40googlegroups.com.

Igor Karelin

unread,
Jun 4, 2020, 7:41:19 AM6/4/20
to Suzuki Tomohiro, Flutter Development (flutter-dev)
Added await:

    await addCategoryToDatabase(newCategory);
});
}
Now receiving infinite spinning circular progress indicator only an in my log I can see cycle of db initialising and adding category:

…….
flutter: *** Executing addCategoryToDatabase in db helper
flutter: *** Initializing Database ***
flutter: *** Executing preloadCategories ***
flutter: *** Executing addCategoryToDatabase in db helper
flutter: *** Initializing Database ***
flutter: *** Executing preloadCategories ***
flutter: *** Executing addCategoryToDatabase in db helper
flutter: *** Initializing Database ***
flutter: *** Executing preloadCategories ***
flutter: *** Executing addCategoryToDatabase in db helper
flutter: *** Initializing Database ***
…….

Suzuki Tomohiro

unread,
Jun 4, 2020, 9:27:57 AM6/4/20
to Igor Karelin, Flutter Development (flutter-dev)
Use breakpoint at the end of “get database” function and debug your app. I guess _database is null.

Also stopping at breakpoints tells you why a certain function is called multiple times. Read stacktrace.

Igor Karelin

unread,
Jun 4, 2020, 11:30:45 AM6/4/20
to Suzuki Tomohiro, Flutter Development (flutter-dev)
In this case I’ll not see the Category data when switch to other screen and back.

Suzuki Tomohiro

unread,
Jun 4, 2020, 12:19:19 PM6/4/20
to Igor Karelin, Flutter Development (flutter-dev)
Would you explain why that happens? (Use debugger and breakpoints.)
Reply all
Reply to author
Forward
0 new messages