【问题标题】:How to load data on app start from file with Flutter and sqflite?如何使用 Flutter 和 sqflite 从文件加载应用程序开始的数据?
【发布时间】:2023-04-08 10:02:01
【问题描述】:

我有一个完整的数据列表,我想在我的应用启动时加载它。我能够提取到 JSON 文件中,因此我可以将其加载到我的表中,但它并没有完全正确加载,而且似乎还被添加了多次。看起来我正在通过资产正确加载文件(打印 _loadIngredients 中的值给了我正确的结果)。但是当它被保存到数据库中时,它只是被保存为一个整数,这就是视图中显示的内容。

我在任何地方都找不到这样的好例子。

我哪里错了?

在我的数据库处理程序中:

class DatabaseHandler{
  DatabaseHandler._();

  static final DatabaseHandler db = DatabaseHandler._();

  static DatabaseHandler get() {
    return db;
  }

  static Database _database;

  final databaseName = "recipe.db";

  DatabaseHandler._createInstance();

  Future<Database> get database async {
    if (_database != null)
      return _database;

    _database = await initDB();
    return _database;
  }


  initDB() async {
    var path = await getDatabasesPath();
    print("Creating tables at path: $path");
    var dbPath = join(path, 'recipe.db');

    Database dbConnection = await openDatabase(dbPath, version: 1,
        onCreate: (Database db, int version) async {
           return db.execute(
             "CREATE TABLE ingredients(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)",
           );
        }
    );

    await _loadIngredients(dbConnection);
    return dbConnection;
  }

  _loadIngredients(Database db) async {
    Batch batch = db.batch();
    List<Map<String, dynamic>> records = await db.query('ingredients');
    print(records);

    String ingredientsJson = await rootBundle.loadString('assets/json/ingredients.json');
    List ingredientsList = json.decode(ingredientsJson);

    ingredientsList.forEach((val) {
      print(val);
      Ingredient ingredient = Ingredient.fromMap(val);
      batch.insert("ingredients", ingredient.toMap(false));
    });

    var results = await batch.commit();
  }

}

我的配料类别:

class Ingredient {
  int id;
  String name;
  String categoryName;
  DateTime dateCreated;

  Ingredient(this.id, this.name, this.categoryName, this.dateCreated);

  Map<String, dynamic> toMap(bool forUpdate) {
    if(dateCreated == null) {
      dateCreated = new DateTime.now();
    }
    var data = {
//      'id': id,  since id is auto incremented in the database we don't need to send it to the insert query.
      'name': utf8.encode(name),
      'category_name': utf8.encode(categoryName),
      'date_created': epochFromDate( dateCreated )
    };
    if(forUpdate){
      data["id"] = this.id;
    }
    return data;
  }

  Ingredient.fromMap(Map map){
    id = map["id"];
    name = map["name"];
    categoryName = map["category_name"];
    dateCreated = map["date_created"];
  }

// Converting the date time object into int representing seconds passed after midnight 1st Jan, 1970 UTC
  int epochFromDate(DateTime dt) {
    return dt.millisecondsSinceEpoch ~/ 1000 ;
  }
// overriding toString() of the note class to print a better debug description of this custom class
  @override toString() {
    return {
      'id': id,
      'name': name,
      'category_name': categoryName,
      'date_created': epochFromDate( dateCreated )
    }.toString();
  }

}

我正在初始化数据库的主页类:

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

  List<Map<String, dynamic>> _allIngredientsInQueryResult = [];

  var notesViewType ;
  @override void initState() {
    super.initState();
    notesViewType = viewType.Staggered;
    DatabaseHandler.db.initDB();
    retrieveAllIngredientsFromDatabase();
  }

@override
  Widget build(BuildContext context) {
    return
      Container(
         child: _ingredientList()
      );
  }

  Widget _ingredientList() {
    return Container(
        child: ListView.separated(
          padding: const EdgeInsets.all(8),
          itemCount: _allIngredientsInQueryResult.length,
          itemBuilder: (BuildContext context, int index) {
            return Container(
              height: 50,
              color: Colors.amber[100],
              child: Center(child: Text('Entry ${_allIngredientsInQueryResult[index]["name"]}')),
            );
          },
          separatorBuilder: (BuildContext context, int index) => const Divider(),
        )
    );
  }

retrieveAllIngredientsFromDatabase() async {
    var _testData = await DatabaseHandler.db.selectAllIngredients();
    setState(() {
      _allIngredientsInQueryResult = _testData;
    });
  }
}

我在应用中看到的图片:

Ingredients json

【问题讨论】:

  • sqlite 中的日期时间字段.. 它类似于整数值
  • 你在哪里显示 int 值?在代码的哪一部分
  • @FloW 这部分代码给了我 int:${_allIngredientsInQueryResult[index]["name"] 我刚刚添加了一个指向我在应用程序中看到的内容的链接。我想这是成分的ID? loadIngredients() 也被多次调用,即使我只初始化数据库一次。

标签: flutter dart sqflite


【解决方案1】:

如果您使用utf8.encode(name),您可以将字符串转换为字节,例如flour = [102, 108, 111, 117, 114] 当你显示这个值时,你还必须设置一个utf8.decode(map["name"])

在您的示例中类似于

Text('Entry ' + utf8.decode(${_allIngredientsInQueryResult[index]["name"]})))

每次您的initDB() 调用时,数据都会再次出现在数据库中。您只能在 Sqlite DB 的 onCreate 部分中执行此操作

initDB() async {
    var path = await getDatabasesPath();
    print("Creating tables at path: $path");
    var dbPath = join(path, 'recipe.db');

    Database dbConnection = await openDatabase(dbPath, version: 1,
        onCreate: (Database db, int version) async {
          await db.execute(
            "CREATE TABLE ingredients(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, category_name TEXT, date_created INTEGER)",
          );

          await _loadIngredients(db);
        }
    );

    return dbConnection;
  }

我也会使用你的 model class 而不是动态地图

定义 _allIngredientsInQueryResult

List<Ingredient> _allIngredientsInQueryResult = new List();

使用 fromMap() 获取 selectAllIngredients

  Future<List<Ingredient>> selectAllIngredients() async {
    var dbClient = await database;
    List<Map> result = await dbClient.query('ingredients');

    List<Ingredient> r_ingredient = result.map((i) => Ingredient.fromMap(i)).toList();

    return r_ingredient;
  }

在fromMap()中设置解码

  Ingredient.fromMap(Map map){
    id = map["id"];
    name = utf8.decode(map["name"]);
    categoryName = utf8.decode(map["category_name"]);
    dateCreated = DateTime.fromMillisecondsSinceEpoch(map["date_created"]);
  }

获取材料

  retrieveAllIngredientsFromDatabase() async {

    DatabaseHandler.db.selectAllIngredients().then((List<Ingredient> r_ingredient) {
      setState(() {
        _allIngredientsInQueryResult = r_ingredient;
      });
    });

  }

在列表视图中显示

Text('Entry ' + _allIngredientsInQueryResult[index].name)

【讨论】:

  • 非常感谢!!
  • 很高兴能帮上忙
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-01
  • 2020-06-19
  • 2019-07-14
  • 2020-10-14
  • 1970-01-01
相关资源
最近更新 更多