skip to Main Content

I see no data from my database on app startup.

I get the impression that nothing was saved, but the database is not empty.

I added a few items, closed the app, reopened the app, and the UI shows empty data.

I am using Future Builder and I am doing refreshAllNames on startup.

Could someone please point out what’s wrong with my code.

Thank you

My Code:

import 'package:flutter/material.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  MyAppState createState() => MyAppState();
}

class DataFields {
  static final List<String> values = [id, name];
  static final String id = '_id';
  static final String name = 'myName';
}

class DataModel {
  int id;
  String name;
  DataModel({required this.id, required this.name});

  DataModel copy(
          {int? id, String? title, String? description, int? isSelected}) =>
      DataModel(id: id ?? this.id, name: name ?? this.name);
  Map<String, Object?> toJson() =>
      {if (id != null) DataFields.id: id, DataFields.name: name};
  static DataModel fromJson(Map<String, Object?> json) => DataModel(
      id: json[DataFields.id] as int, name: json[DataFields.name] as String);
}

class DBHelper {
  final String myTable = 'myDataTable';
  static const String myDatabase = 'myDB.db';

  DBHelper._init();
  static final DBHelper instance = DBHelper._init();
  static Database? db;

  Future<Database> get dataBase async {
    if (db != null) {
      return db!;
    } else {
      db = await initDB(myDatabase);
      return db!;
    }
  }

  Future<Database> initDB(String filePath) async {
    final dbPath = await getDatabasesPath();
    final path = join(dbPath, filePath);
    return await openDatabase(path, version: 1, onCreate: createDB);
  }

  Future createDB(Database db, int version) async {
    var idType = 'INTEGER PRIMARY KEY AUTOINCREMENT';
    var textType = 'TEXT NOT NULL';
    await db.execute('''CREATE TABLE $myTable (${DataFields.id} $idType,${DataFields.name} $textType)''');
  }

  Future<DataModel> create(DataModel datamodel) async {
    final db = await instance.dataBase;
    final id = await db.insert(myTable, datamodel.toJson());
    return datamodel.copy(id: id);
  }

  Future<DataModel> readData(int id) async {
    final db = await instance.dataBase;
    final maps = await db.query(myTable,
        columns: DataFields.values,
        where: '${DataFields.id} = ?',
        whereArgs: [id]);
    if (maps.isNotEmpty) {
      return DataModel.fromJson(maps.first);
    } else {
      throw Exception('ID $id not found');
    }
  }

  Future<List<DataModel>> readAllNames() async {
    final db = await instance.dataBase;
    final result = await db.rawQuery('SELECT * FROM $myTable');
    final list = result.map((json) => DataModel.fromJson(json)).toList();
    if (list.isNotEmpty)
      return list;
    else
      throw Exception('Empty List');
  }

  Future<int> countAllDataRows() async {
    final db = await instance.dataBase;
    var x = await db.rawQuery('SELECT COUNT(1) FROM $myTable');
    return x.length;
  }

  Future<int> update(DataModel datamodel) async {
    final db = await instance.dataBase;
    return db.update(myTable, datamodel.toJson(),
        where: '${DataFields.id} = ?', whereArgs: [datamodel.id]);
  }

  Future<int> delete(int id) async {
    final db = await instance.dataBase;
    return await db
        .delete(myTable, where: '${DataFields.id} = ?', whereArgs: [id]);
  }

  Future close() async {
    final db = await instance.dataBase;
    db.close();
  }
}

class MyAppState extends State<MyApp> {
  TextEditingController mc = TextEditingController();
  static late List<DataModel> mylist = <DataModel>[];
  int index = 0;
  int myindex = 0;
  bool isLoading = false;

  @override
  void initState() {
    super.initState();
    refreshNames();
  }

  @override
  void dispose() {
    mc.dispose();
    DBHelper.instance.close();
    super.dispose();
  }

  Future refreshNames() async {
    setState(() => isLoading = true);
    mylist = await DBHelper.instance.readAllNames();
    setState(() => isLoading = false);
  }

  addItem() {
    setState(() {
      if (mc.text.isNotEmpty) {
        index++;
        mylist.add(DataModel(id: index, name: mc.text));
        DBHelper.instance.create(DataModel(id: index, name: mc.text));
        refreshNames();
      }
    });
  }

  removeItem() {
    setState(() {
      if (index > 0) {
        index;
        mylist.removeAt(index);
        DBHelper.instance.delete(index);
        refreshNames();
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    Widget space = SizedBox(width: 100, height: 20, child: Text(""));
    Widget myinput = TextField(
        controller: mc,
        decoration: InputDecoration(border: OutlineInputBorder(), labelText: 'Name'));
    Widget btnAdd = ElevatedButton(onPressed: addItem, child: Text('Add'));
    Widget btnRemove = ElevatedButton(onPressed: removeItem, child: Text('Remove'));

    Widget newList = SizedBox(
        width: 800,
        height: 500,
        child: FutureBuilder<List<DataModel>?>(builder:
            (BuildContext context, AsyncSnapshot<List<DataModel>?> snapshot) {
              return ListView.separated(
                padding: const EdgeInsets.all(8),
                itemCount: mylist.length,
                itemBuilder: (BuildContext context, int index) {
                  return Container(
                    height: 100,
                    child: Center(child: Text('${mylist[index].name}')),
                  );
                },
                separatorBuilder: (BuildContext context, int index) => const Divider(),
              );
        }));

    return MaterialApp(
        home: Scaffold(
            resizeToAvoidBottomInset: false,
            body: SingleChildScrollView(scrollDirection: Axis.vertical,
                child: Column(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                      Container(
                          padding: const EdgeInsets.all(5),
                          child: SingleChildScrollView(
                              child: Column(
                                  mainAxisAlignment:MainAxisAlignment.spaceEvenly,
                                  children: <Widget>[
                                space,space,myinput,space,btnAdd,space,btnRemove,space,newList,space
                              ])))
                    ]))));
  }
}

2

Answers


  1. What seems as issue here is your readAllNames() function, this function only select the myName column from the table. but, the DataModel class has two columns: id and name. So, the fromJson() method of DataModel is not able to create a DataModel object from the result of this query since it expects both id and name fields.

    Here are some changes you could try:

     Future<List<DataModel>> readAllNames() async {
          final db = await instance.dataBase;
          final result = await db.rawQuery('SELECT * FROM $myTable');
          final list = result.map((json) => DataModel.fromJson(json)).toList();
          if (list.isNotEmpty)
            return list;
          else
            throw Exception('Empty List');
        }
    
    Login or Signup to reply.
  2. There is error while mapping data to class, you have not select id from table, whereas id field is not null in DataModel

    Future<List<DataModel>> readAllNames() async {
        final db = await instance.dataBase;
        final result = await db.rawQuery('SELECT _id,myName FROM $myTable');
        final list = result.map((json) => DataModel.fromJson(json)).toList();
        if (list.isNotEmpty)
          return list;
        else
          throw Exception('Empty List');
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search