如何使用异步方法构建列表对象?

时间:2018-07-19 14:17:08

标签: sqlite asynchronous dart flutter

我收到一条错误消息,提示.length方法正在调用空对象_genreList。

我正在使用一种异步方法从本地资产sqlite数据库获取数据,该数据库是流派列表。然后,我使用ListView.builder以便在屏幕上显示该列表。这是获取数据的代码...

Future getGenreData() async {

    Directory documentsDirectory = await getApplicationDocumentsDirectory();

    String path = join(documentsDirectory.path, "asset_sample_sqlite.db");

    ByteData data = await rootBundle.load(join("assets", "sample_sqlite.db"));

    List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);

    await new File(path).writeAsBytes(bytes);

    Database db = await openDatabase(path);

    _genreList = await db.rawQuery('SELECT genre_name[] FROM tbl_genres');

    print(_genreList);

    await db.close();
  }

如何在build Widget方法中使用此方法,以便在使用ListView.builder时可以访问_genreList?像这样..

@override
  Widget build(BuildContext context) {

    return Scaffold(

      body: new ListView.builder(
          itemCount: _genreList.length, //need to access the genreList here
          itemBuilder: (BuildContext context, int index) {
            return new Card(
              child: new ListTile(
                title: new Text("${_genreList[index]}"),
                onTap: () {
                  Navigator.push(context,
                  MaterialPageRoute(
                    builder: (context) => BookPage(id: index),
                  ),
                  );
                }
              ),
            );
          }
      ),
    );
  }

这里的最终目标是显示一个流派列表(来自我的sqlite数据库中的tbl_genres),将能够将数据传递到下一页以显示书籍列表(来自我的sqlite数据库中的tbl_books)与该类型有关。

1 个答案:

答案 0 :(得分:1)

异步编程的全部要点是,当您在后台执行耗时的工作时,您的用户界面可以保持活动状态。因此,您需要(并且希望)在加载应用程序时显示类似CircularProgressIndicator或什至空白页(例如Container)的内容。

至少有两种方法可以做到这一点:

  1. 使窗口小部件为有状态,并引入状态字段loading,您将其初始化为true,并在数据(在另一个字段中)准备就绪时设置为false。您的代码如下所示:
import 'package:flutter/material.dart';

class GenresPage extends StatefulWidget {
  @override
  _GenresPageState createState() => _GenresPageState();
}

class _GenresPageState extends State<GenresPage> {
  bool loading;
  List<String> genreNames;

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

    loading = true;
    getGenreData();
  }

  Future getGenreData() async {
    final genreData = await actuallyGetThoseNames();

    setState(() {
      genreNames = genreData;
      loading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: !loading ? new ListView.builder(
        itemCount: genreNames.length,
        itemBuilder: (context, index) {
          return new Card(
            child: new ListTile(
              title: new Text("${genreNames[index]}"),
            ),
          );
        },
      ) : CircularProgressIndicator(), // or Container()
    );
  }
}
  1. 使用FutureBuilder。因此,您将需要重构getGenreData方法以将列表作为Future<List<String>>返回。