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,或者至少在您真正需要检查该值的小部件树的上方