Flutter:SQLite 的收藏夹功能 - 首次加载问题
Flutter: Favourites feature with SQLite - Issue with first load
我创建了一个详细信息页面并使用了 Medium 文章中的示例。我能够成功地执行 CRUD 操作。
当我加载 DetailsPage 时,我想检查 table 是否有 ID,如果有,则将收藏夹图标设为黄色。
class _DetailPageState extends State<DetailPage> {
bool isFav = false;
MyImpData myData;
_DetailPageState(this.myData);
// reference to our single class that manages the database
final dbHelper = DatabaseHelper.instance;
@override
Widget build(BuildContext context) {
Widget heading = new Container(...),);
Widget middleSection = new Expanded(...);
Widget bottomBanner = new Container(...),);
Widget body = new Column(...);
final makeBottom = Container(
height: 55.0,
child: BottomAppBar(
color: Color.fromRGBO(58, 66, 86, 1.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: buildIcon(),
onPressed: () {
_insertOrDelete(myData.id);
},
),
IconButton(
icon: Icon(Icons.share, color: Colors.white),
onPressed: () => share(context, myData),
)
],
),
),
);
return Scaffold(
appBar: AppBar(...),
body: Container(...),
bottomNavigationBar: makeBottom,
);
}
Icon buildIcon() {
if (isFav) {
return Icon(Icons.favorite, color: Colors.yellow);
} else {
return Icon(Icons.favorite_border, color: Colors.white);
}
}
void share(BuildContext context, MyImpData myData) {...}
void _insert() async {
// row to insert
Map<String, dynamic> row = {
DatabaseHelper.columnName: myData.name,
DatabaseHelper.columnDesc: myData.desc,
DatabaseHelper.columnLoc: myData.location,
DatabaseHelper.columnId: myData.id
};
final id = await dbHelper.insert(row);
print('inserted row id: $id');
}
void _checkFav(String checkId) async {
final rowsPresent = await dbHelper.queryForFav(checkId);
if (rowsPresent > 0) {
print('success');
isFav = true;
} else {
print('Nothing found so inserting you dodo');
isFav = false;
//_insert();
}
//rowsPresent.forEach((row) => print(row));
}
void _insertOrDelete(String id) async {
final rowsPresent = await dbHelper.queryForFav(id);
if (rowsPresent > 0) {
print('Its favourite and removing it');
_delete();
isFav = false;
} else {
print('Nothing found so inserting you dodo');
_insert();
isFav = true;
}
}
void _delete() async {...}
}
DBHelper.dart 文件具有以下 queryForFav(id)
//Raw query to check if it is in the favourites
Future<int> queryForFav(String checkId) async {
Database db = await instance.database;
int noOfRows = 0;
try {
noOfRows = Sqflite.firstIntValue(await db.rawQuery(
'SELECT COUNT(*) FROM $table WHERE $columnId = ?',
['$checkId']));
} catch (e) {
print(e);
}
return noOfRows;
}
我的尝试是创建一个标志 isFav 并在我检查数据库时设置它。但是,这始终是错误的,因为没有执行任何查询。只有当我按下按钮时,才会执行实际的数据库查询。
任何帮助,将不胜感激。
为此 class
更改 IconButton(child, buildIcon(), ...)
class FavIconWidget extends StatefulWidget {
final MyImpData myData;
FavIconWidget(this.myData);
@override
_FavIconWidgetState createState() => _FavIconWidgetState();
}
class _FavIconWidgetState extends State<FavIconWidget> {
final dbHelper = DatabaseHelper.instance;
Future<bool> get isFav async {
final rowsPresent = await dbHelper.queryForFav(widget.myData.id);
if (rowsPresent > 0) {
print('Its favourite and removing it');
await _delete();
return false;
} else {
print('Nothing found so inserting you dodo');
await _insert();
return true;
}
}
void _insert() async {
// row to insert
Map<String, dynamic> row = {
DatabaseHelper.columnName: widget.myData.name,
DatabaseHelper.columnDesc: widget.myData.desc,
DatabaseHelper.columnLoc: widget.myData.location,
DatabaseHelper.columnId: widget.myData.id
};
final id = await dbHelper.insert(row);
print('inserted row id: $id');
}
void _delete() async {}
@override
Widget build(BuildContext context) {
return FutureBuilder<bool>(
future: isFav,
initialData: false,// you can define an initial value while the db returns the real value
builder: (context, snapshot) {
if(snapshot.hasError) return const Icon(Icons.error, color: Colors.red); //just in case the db return an error
return IconButton(
icon: snapshot.data ? const Icon(Icons.favorite, color: Colors.yellow) :
Icon(Icons.favorite, color: Colors.white),
onPressed: () => setState(() {})
);
});
}
}
基本上它用 FutureBuilder 包装图标,这是一个等待未来值的特殊小部件(在本例中是数据库行的 return),您可以在等待时给它一个初始值(在在这种情况下,我给了它一个 false),但你可以忽略它并检查是否有一个值 snapshot.hasData 和 return 一个 CircularProgressIndicator 告诉用户你正在获取数据
return FutureBuilder<bool>(
future: isFav,
initialData: false,// you can define an initial value while the db returns the real value
builder: (context, snapshot) {
if(snapshot.hasError) return const Icon(Icons.error, color: Colors.red); //just in case the db return an error
if(snapshot.hasData)
return IconButton(
icon: snapshot.data ? const Icon(Icons.favorite, color: Colors.yellow) :
Icon(Icons.favorite, color: Colors.white),
onPressed: () => setState(() {})
);
return CircularProgressIndicator(); //if there is no initial value and the future is not yet complete
});
我制作了这个 StatefulWidget,所以当您按下按钮时,它会设置状态并重新运行 isFav 未来再次检查数据库(但它只是重建这个图标按钮,而不是您的整个页面)。如果您想根据该 isFav 值而不是仅根据图标更新整个页面,那么您将必须在脚手架的所有主体中使用该 FutureBuilder,或者至少在您真正需要检查该值的小部件树的上方
我创建了一个详细信息页面并使用了 Medium 文章中的示例。我能够成功地执行 CRUD 操作。
当我加载 DetailsPage 时,我想检查 table 是否有 ID,如果有,则将收藏夹图标设为黄色。
class _DetailPageState extends State<DetailPage> {
bool isFav = false;
MyImpData myData;
_DetailPageState(this.myData);
// reference to our single class that manages the database
final dbHelper = DatabaseHelper.instance;
@override
Widget build(BuildContext context) {
Widget heading = new Container(...),);
Widget middleSection = new Expanded(...);
Widget bottomBanner = new Container(...),);
Widget body = new Column(...);
final makeBottom = Container(
height: 55.0,
child: BottomAppBar(
color: Color.fromRGBO(58, 66, 86, 1.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: buildIcon(),
onPressed: () {
_insertOrDelete(myData.id);
},
),
IconButton(
icon: Icon(Icons.share, color: Colors.white),
onPressed: () => share(context, myData),
)
],
),
),
);
return Scaffold(
appBar: AppBar(...),
body: Container(...),
bottomNavigationBar: makeBottom,
);
}
Icon buildIcon() {
if (isFav) {
return Icon(Icons.favorite, color: Colors.yellow);
} else {
return Icon(Icons.favorite_border, color: Colors.white);
}
}
void share(BuildContext context, MyImpData myData) {...}
void _insert() async {
// row to insert
Map<String, dynamic> row = {
DatabaseHelper.columnName: myData.name,
DatabaseHelper.columnDesc: myData.desc,
DatabaseHelper.columnLoc: myData.location,
DatabaseHelper.columnId: myData.id
};
final id = await dbHelper.insert(row);
print('inserted row id: $id');
}
void _checkFav(String checkId) async {
final rowsPresent = await dbHelper.queryForFav(checkId);
if (rowsPresent > 0) {
print('success');
isFav = true;
} else {
print('Nothing found so inserting you dodo');
isFav = false;
//_insert();
}
//rowsPresent.forEach((row) => print(row));
}
void _insertOrDelete(String id) async {
final rowsPresent = await dbHelper.queryForFav(id);
if (rowsPresent > 0) {
print('Its favourite and removing it');
_delete();
isFav = false;
} else {
print('Nothing found so inserting you dodo');
_insert();
isFav = true;
}
}
void _delete() async {...}
}
DBHelper.dart 文件具有以下 queryForFav(id)
//Raw query to check if it is in the favourites
Future<int> queryForFav(String checkId) async {
Database db = await instance.database;
int noOfRows = 0;
try {
noOfRows = Sqflite.firstIntValue(await db.rawQuery(
'SELECT COUNT(*) FROM $table WHERE $columnId = ?',
['$checkId']));
} catch (e) {
print(e);
}
return noOfRows;
}
我的尝试是创建一个标志 isFav 并在我检查数据库时设置它。但是,这始终是错误的,因为没有执行任何查询。只有当我按下按钮时,才会执行实际的数据库查询。 任何帮助,将不胜感激。
为此 class
更改 IconButton(child, buildIcon(), ...)class FavIconWidget extends StatefulWidget {
final MyImpData myData;
FavIconWidget(this.myData);
@override
_FavIconWidgetState createState() => _FavIconWidgetState();
}
class _FavIconWidgetState extends State<FavIconWidget> {
final dbHelper = DatabaseHelper.instance;
Future<bool> get isFav async {
final rowsPresent = await dbHelper.queryForFav(widget.myData.id);
if (rowsPresent > 0) {
print('Its favourite and removing it');
await _delete();
return false;
} else {
print('Nothing found so inserting you dodo');
await _insert();
return true;
}
}
void _insert() async {
// row to insert
Map<String, dynamic> row = {
DatabaseHelper.columnName: widget.myData.name,
DatabaseHelper.columnDesc: widget.myData.desc,
DatabaseHelper.columnLoc: widget.myData.location,
DatabaseHelper.columnId: widget.myData.id
};
final id = await dbHelper.insert(row);
print('inserted row id: $id');
}
void _delete() async {}
@override
Widget build(BuildContext context) {
return FutureBuilder<bool>(
future: isFav,
initialData: false,// you can define an initial value while the db returns the real value
builder: (context, snapshot) {
if(snapshot.hasError) return const Icon(Icons.error, color: Colors.red); //just in case the db return an error
return IconButton(
icon: snapshot.data ? const Icon(Icons.favorite, color: Colors.yellow) :
Icon(Icons.favorite, color: Colors.white),
onPressed: () => setState(() {})
);
});
}
}
基本上它用 FutureBuilder 包装图标,这是一个等待未来值的特殊小部件(在本例中是数据库行的 return),您可以在等待时给它一个初始值(在在这种情况下,我给了它一个 false),但你可以忽略它并检查是否有一个值 snapshot.hasData 和 return 一个 CircularProgressIndicator 告诉用户你正在获取数据
return FutureBuilder<bool>(
future: isFav,
initialData: false,// you can define an initial value while the db returns the real value
builder: (context, snapshot) {
if(snapshot.hasError) return const Icon(Icons.error, color: Colors.red); //just in case the db return an error
if(snapshot.hasData)
return IconButton(
icon: snapshot.data ? const Icon(Icons.favorite, color: Colors.yellow) :
Icon(Icons.favorite, color: Colors.white),
onPressed: () => setState(() {})
);
return CircularProgressIndicator(); //if there is no initial value and the future is not yet complete
});
我制作了这个 StatefulWidget,所以当您按下按钮时,它会设置状态并重新运行 isFav 未来再次检查数据库(但它只是重建这个图标按钮,而不是您的整个页面)。如果您想根据该 isFav 值而不是仅根据图标更新整个页面,那么您将必须在脚手架的所有主体中使用该 FutureBuilder,或者至少在您真正需要检查该值的小部件树的上方