Reputation: 81
Trying to change access to database from:
simply initializing access to data initState
and then showing results in ListView.builder
to
ListView.builder
inside the FutureBuilder
.
However I lost my way in this FutureBuilder and my list is empty. I guess my problem is inside updateAndGetList()
.
In console I am getting this:
flutter: AsyncSnapshot<List<Word>>(ConnectionState.done, null, , #0 _RandomWordsState.updateAndGetList.<anonymous closure> (package:myapplesson/main.dart:115:7)
Can somebody help or nudge me in a right direction?π₯²
Here my main.dart
DatabaseHelper dbHelper = DatabaseHelper.instance;
final _suggestions = <Word>[];
@override
void initState() {
super.initState();
// initial load
_listFuture = updateAndGetList();
}
late Future<List<Word>> _listFuture;
void refreshList() {
// reload
setState(() {
_listFuture = updateAndGetList();
});
}
//I GUESS I AM DOING SOMETHING WRONG HERE!?πππ
Future<List<Word>> updateAndGetList() async {
await DatabaseHelper.instance.database;
// return the list here
return dbHelper.getAllWords().then((rows) {
setState(() {
rows?.forEach((row) { _suggestions.add(Word.map(row));});
});
throw '';
});
}
Widget _buildSuggestions() {
return FutureBuilder<List<Word>>(
future: _listFuture,
builder: (BuildContext context, AsyncSnapshot<List<Word>> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: _suggestions.length,
itemBuilder: (context, i) {
if (i.isOdd) return const Divider();
final index = i ~/ 2;
if (index >= _suggestions.length) {
_suggestions.addAll(_suggestions.take(10));
}
return _buildRow(_suggestions[index]);
});
}else if (snapshot.hasError) {
return Text("Oops!");
}
return Center(child: CircularProgressIndicator());
},
);
}
Widget _buildRow(Word pair) {
return ListTile(
title: Text(
pair.word1
),
subtitle: Text(
pair.meaning
),
);
}
Before the changes were done everything worked this way:
//perfectly workedπ
@override
void initState() {
super.initState();
dbHelper.getAllWords().then((rows) {
setState(() {
rows?.forEach((row) { _suggestions.add(Word.map(row));});
});
});
}
Widget _buildSuggestions() {
return ListView.builder(
itemCount: _suggestions.length,
itemBuilder: (context, i) {
if (i.isOdd) return const Divider();
final index = i ~/ 2;
if (index >= _suggestions.length) {
_suggestions.addAll(_suggestions.take(10));
}
return _buildRow(_suggestions[index]);
});
}
Widget _buildRow(Word pair) {
return ListTile(
title: Text(
pair.word1
),
subtitle: Text(
pair.meaning
),
);
}
This is my Database_helper.dart
...
Future<List<Map<String, dynamic>>?> getAllWords() async {
Database? db = await instance.database;
var result = await db?.query(table);
return result?.toList();
}
...
Upvotes: 1
Views: 745
Reputation: 3001
In your updateAndGetList
function, you are expected to return a Future<List<Word>>
. Instead, you don't return anything (but set the state instead). Consider adapting it to look a bit like the following:
Future<List<Word>> updateAndGetList() async {
await DatabaseHelper.instance.database;
// return the list here
return dbHelper.getAllWords().then((rows) {
// build the list of words and then return it!
List<Word> res = [];
for (var row in rows) {
res.add(Word.map(row));;
}
return res;
});
}
You can now access this list of words from your snapshot in your future builder
return FutureBuilder<List<Word>>(
future: _listFuture,
builder: (BuildContext context, AsyncSnapshot<List<Word>> snapshot) {
if (snapshot.hasData) {
// the word list as retrieved from your future
List<Word> wordList = snapshot.data;
return ListView.builder(
itemCount: wordList.length,
itemBuilder: (context, i) {
if (i.isOdd) return const Divider();
final index = i ~/ 2;
if (index >= wordList.length) {
wordList.addAll(wordList.take(10));
}
// use the word listto build your rows
return _buildRow(wordList[index]);
});
}else if (snapshot.hasError) {
return Text("Oops!");
}
return Center(child: CircularProgressIndicator());
},
);
No need to keep a separate variable for your suggestions.
Moreover, you won't really need your _listFuture
variable, unless you require it somewhere else. In your FutureBuilder
you can simply use
return FutureBuilder<List<Word>>(
future: updateAndGetList(),
builder: ...
);
Upvotes: 2