Flutterアプリにデータを保存するためにsqliteを使用しています。フィルターチップで開くモーダルボトムシートがあり、フィルターチップを選択すると、データベースにアイテムが追加されます。アイテムがすでに存在する場合、フィルターチップがチェックされます。データベース関数を呼び出してアイテムがすでに存在するかどうかを確認すると、次のエラーが発生します。
Asyncとawaitの両方を使用してみました。
データベースクエリコード:
// FIND TAG
findTag(int tagId) async {
var dbConnection = await db;
var res = await dbConnection.query("$TABLE_NAME", where: "tagId = ?", whereArgs: [tagId]);
return res.isNotEmpty ? true : false ;
}
モーダルボトムシートウィジェットコンテナコード:
Widget build(BuildContext context) {
setState(() {
_index = widget.index;
_list =widget.list;
});
return new Container(
padding: new EdgeInsets.all(27.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget> [
new Text(_list[_index]["title"], style: new TextStyle( fontWeight: FontWeight.bold, fontSize: 22),),
new Text(_list[_index]["description"]),
getFilterChipsWidgets(),
],
),
);
}
getFilterChipsWidgets()
async {
List<Widget> tagsList = new List<Widget>();
for(var i=0; i<_list[_index]["tags"].length; i++) {
var dbHelper = DBHelper();
int id = int.parse(_list[_index]["tags"][i]["id"]);
var exist = await dbHelper.findTag(id);
FilterChip item = new FilterChip(
label: Text(_list[_index]["tags"][i]["name"].toString(),),
selected: exist,
onSelected: (bool newValue) {
if(newValue) {
dbHelper.addNewTag(id);
} else {
dbHelper.deleteNewTag(id);
}
},
);
tagsList.add(item);
}
return Wrap(
spacing: 8.0, // gap between adjacent chips
runSpacing: 4.0, // gap between lines
children: tagsList,
);
}
GetFilterChipsWidgets()は非同期関数であるため、Futureを返します。将来を待ち、ウィジェットを保存して、完了したらsetStateを一覧表示して呼び出すことができます。または、次のようにFutureBuilderでラップします。
children: <Widget> [
new Text(_list[_index]["title"], style: new TextStyle(fontWeight: FontWeight.bold, fontSize: 22),),
new Text(_list[_index]["description"]),
FutureBuilder<Widget>(
future: getFilterChipsWidgets,
builder: (BuildContext context, AsyncSnapshot<Widget> snapshot){
if(snapshot.hasData)
return snapshot.data;
return Container(child: CircularProgressIndicator());
}
),
],
誤って関数async
を割り当て、関数ブロック内でawait
プロセスを使用している場所がないことも時々見られます。
同様のシナリオがすでに発生しており、この未使用のasync
を関数から削除することで、上記の問題を解決しました。
関数をasync
にすると、関数リクエスターはそれをFuture<T>
の方法で処理するので、注意してください。