Как загрузить данные о запуске приложения из файла с Flutter и sqflite? - PullRequest
2 голосов
/ 26 апреля 2020

У меня есть полный список данных, которые я хочу загрузить в свое приложение при запуске. Мне удалось извлечь в файл JSON, чтобы я мог загрузить его в свою таблицу, но он загружается не совсем правильно и, кажется, добавляется несколько раз. Похоже, что я загружаю в файл правильно через активы (печать значений в _loadIngredients дает мне правильные результаты). Но когда он сохраняется в БД, он просто сохраняется как целое число, и это то, что отображается в представлении.

Я не могу найти хороший пример этого нигде.

Где я ошибаюсь?

В моем DatabaseHandler:

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 list

Ингредиенты json

1 Ответ

1 голос
/ 29 апреля 2020

если вы используете utf8.encode(name), вы преобразуете свою строку в байты что-то вроде flour = [102, 108, 111, 117, 114], и когда вы отображаете эти значения, вы также должны установить utf8.decode(map["name"])

в вашем примере что-то вроде

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

каждый раз, когда ваш initDB() звонит, Данные снова поступают в БД. Вы можете сделать это только в части onCreate Sqlite DB

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, а не карту dynima c

Define _allIngredientsInQueryResult

List<Ingredient> _allIngredientsInQueryResult = new List();

get selectAllIngredients с установленным параметром fromMap ()

  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"]);
  }

get Ingredients

  retrieveAllIngredientsFromDatabase() async {

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

  }

в списке

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