Zebrastian
Zebrastian

Reputation: 491

Error when populating FutureBuilder with data from sqflite

I have an SQLite database with movies. I'm following this example.

I want to show all the movies in a ListView.

I try to populate the ListView using a FutureBuilder like in the example, but where I assign the future of the FutureBuilder, it throws the following exception:

type 'Future<dynamic>' is not a subtype of type 'Future<List<Movie>>'

I find this strange as my function that I use in the FutureBuilder returns a List<Movie> and not dynamic.

What could be causing this error?

Database:

class MovieDatabase {
  MovieDatabase._();
  static final MovieDatabase db = MovieDatabase._();
  static Database _database;

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

  initDB() async {
    Directory documentsDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentsDirectory.path, "MovieDB.db");
    return await openDatabase(path, version: 1, onOpen: (db) {},
        onCreate: (Database db, int version) async {
      await db.execute("CREATE TABLE Movie ("
          ...
          ")");
    });
  }

  getAllMovies() async {
    final db = await database;
    var res = await db.query("Movie");
    List<Movie> list =
        res.isNotEmpty ? res.map((m) => Movie.fromSqLite(m)).toList() : [];
    return list;
  }
  ...
}

Widget:

@override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: <Widget>[
          FutureBuilder<List<Movie>>(
            future: MovieDatabase.db.getAllMovies(), // This line causes the error
            initialData: List(),
            builder:
                (BuildContext context, AsyncSnapshot<List<Movie>> snapshot) {
              return snapshot.hasData
                  ? ListView.builder(
                      itemCount: snapshot.data.length,
                      itemBuilder: (BuildContext context, int position) {
                        Movie movie = snapshot.data[position];
                        return Card(
                          child: ListTile(
                            title: Text(movie.title),
                          ),
                        );
                      },
                    )
                  : Center(
                      child: CircularProgressIndicator(),
                    );
            },
          ),
        ],
      ),
    );
  }

Upvotes: 3

Views: 1478

Answers (1)

Mohamad Assem Nasser
Mohamad Assem Nasser

Reputation: 1109

The method getAllMovies() has no specific return type, so, by default, it will return:

  1. void: if there is no return statement.
  2. dynamic: if there is a return statement. Int if it returns int, String if it returns String...

In your case it is returning a list but dart does not know that until the method is called. The widget FutureBuilder requires a function that needs to explicitly return a List of Movies, not a dynamic.

Just add a List of Movies as a return type to getAllMovies() method and you should be good to go:

 List<Movies> getAllMovies() async {
    final db = await database;
    var res = await db.query("Movie");
    List<Movie> list =
        res.isNotEmpty ? res.map((m) => Movie.fromSqLite(m)).toList() : [];
    return list;
  }

Upvotes: 4

Related Questions