XKCD
XKCD

Reputation: 132

Using the value returned from a Future in a class in dart

Hello i have the following code

class TodoProvider {
  Database db;


  TodoProvider() {
    _initDatabase();
    print("Db is >>>>> $db");
  }

  void _initDatabase() async {
    final database = await AppDatabase().connect();
    db = database;
  }

  Future<Todo> insertTodo(Todo todo) async {
    todo.id = await db.insert('todo', todo.toMap());
    return todo;
  }

  Future<Todo> getTodo(int id) async {
    List<Map<String, dynamic>> maps =
        await db.query('todo', where: 'id=?', whereArgs: [id]);
    if (maps.length > 0) {
      return Todo.fromMap(maps.first);
    }
    return null;
  }

  Future<int> deleteTodo(int id) async {
    return await db.delete('todo', where: 'id=?', whereArgs: [id]);
  }

  Future<int> updateTodo(Todo todo) async {
    return await db
        .update('todo', todo.toMap(), where: 'id=?', whereArgs: [todo.id]);
  }

  Future close() async => db.close();
}

The AppDatabase is a class that exposes the connect() method which returns a future.

The Goal is to assign the value returned from AppDatabase into the db class variable

Most methods in the TodoProvider class relays on the db class variable to work with the database.

The problem is that class variable db is always null

Upvotes: 0

Views: 50

Answers (1)

julemand101
julemand101

Reputation: 31309

You code right now depends on the db variable is being set which happens inside an async operation. There are two ways to fix this:

Use static builder method

You can create a private constructor which can be called by a static method which are allowed to return Future<TodoProvider> which the user can await on.

class TodoProvider {
...
  TodoProvider._(this.db) {
    print("Db is >>>>> $db");
  }

  static Future<TodoProvider> getInstance() async {
    return TodoProvider._(await AppDatabase().connect());
  }
...
}

Use the Future as member of the class

This is not the prettiest solution but still a way to do it. Since you are allowed to await on the same Future multiple times, you can just await every time you need to access the Database object.

class TodoProvider {
  Future<Database> _db;

  TodoProvider() {
    _initDatabase();
    print("Db is >>>>> $db");
  }

  void _initDatabase() {
    _db = AppDatabase().connect();
  }

  Future<Todo> insertTodo(Todo todo) async {
    final db = await _db;
    todo.id = await db.insert('todo', todo.toMap());
    return todo;
  }

  Future<Todo> getTodo(int id) async {
    final db = await _db;
    List<Map<String, dynamic>> maps =
    await db.query('todo', where: 'id=?', whereArgs: [id]);
    if (maps.length > 0) {
      return Todo.fromMap(maps.first);
    }
    return null;
  }

  Future<int> deleteTodo(int id) async {
    final db = await _db;
    return await db.delete('todo', where: 'id=?', whereArgs: [id]);
  }

  Future<int> updateTodo(Todo todo) async {
    final db = await _db;
    return await db
        .update('todo', todo.toMap(), where: 'id=?', whereArgs: [todo.id]);
  }

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

Upvotes: 1

Related Questions