【问题标题】:A value of type 'Future<List>' can't be assigned to a variable of type 'List'“Future<List>”类型的值不能分配给“List”类型的变量
【发布时间】:2021-08-29 23:51:44
【问题描述】:

我真的是 Flutter 和 SQLite 的新手。 我需要将从数据库中获取的一些数据存储到全局变量中(在此代码中,它是一个局部变量,仅用于示例),我不知道:

  1. 我能做到的最佳点在哪里(现在我把它放在主页的 initState 方法中);
  2. 如何将未来的数据存储在一个没有未来的变量中。

以下是数据提取的方法

class ObjectRepository {
  ObjectRepository._(); 
  static final ObjectRepository instance = ObjectRepository._();

  Future<List<Map>> select(Database db, String tableName, {List<String> fields}) async {
        sql = 'SELECT ' + (fields != null ? fields.toString() : '* ');
        sql = sql + 'FROM $tableName';
    
        final List<Map> list = await db.rawQuery(sql);
    
        return list;
  }
}

下面是我将 future> 放入 List 的地方(我知道我不能,实际上 IDE 给了我这个错误 A value of type 'Future>>' 不能分配给 'List>' 类型的变量。请尝试更改变量的类型,或将右侧类型转换为 'List>'

我什至尝试强制转换它,但在运行时遇到了类似的问题 "type 'Future>>' is not a subtype of type 'List>'类型转换"

class HomePage extends StatefulWidget {
  HomePage({Key key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  void initState() {
    super.initState();

    DBProvider.instance.openDB(globalConstants.dbName);
    List<Map> list = ObjectRepository.instance.select(DBProvider.instance.database, 'tCars') as List<Map>;
  }

  @override
  void dispose() {
    DBProvider.instance.closeDB();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: CustomAppBar(title: Text('Cars')),
      drawer: CustomDrawer(),
      body: CustomBody(),
    );
  }
}

知道如何解决吗?非常感谢,伙计们。

【问题讨论】:

  • 这是一个未来。你必须在某个地方等待它。不要那么着急。 :)

标签: flutter sqlite casting future


【解决方案1】:

错误是因为instant.select 函数返回Future&lt;List&lt;Map&gt;&gt;,但您正试图将其分配给List&lt;Map&gt;,因此您必须等待future 完成。但initState 不是async 函数。因此你不能在那里await。但是您可以在 future 上使用 then 方法(当用该值完成 future 时调用该方法)。并将callback(您要使用该值执行的操作)给 then 方法。但是在使用if 语句之前,您必须仔细检查list 是否为null,因为它最初设置为null。

    class HomePage extends StatefulWidget {
    
      HomePage({Key key}) : super(key: key);
    
      List<Map>? list;
      @override
      _HomePageState createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage> {
      @override
      void initState() {
        super.initState();
    
        DBProvider.instance.openDB(globalConstants.dbName);
        ObjectRepository.instance.select(DBProvider.instance.database, 'tCars').then((result){
           if(mounted) {
             setState((){ list = result});
              }else { list = result}
            });
      }
    
      @override
      void dispose() {
        DBProvider.instance.closeDB();
    
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: CustomAppBar(title: Text('Cars')),
          drawer: CustomDrawer(),
          body: CustomBody(),
        );
      }
    }

如果您想将您的列表用于小部件(例如:ListView),则立即执行此操作。考虑使用FutureBuilder,它采用futurebuilder 函数根据您给它的未来状态返回适当的widget。例如,

 FutureBuilder<List<Map>>(
   future: ObjectRepository.instance.select(DBProvider.instance.database, 'tCars') // your future here,
builder : (context, snapshot) {
       if (snapshot.hasError) return ErorrScreen();
       if (snapshot.hasData) return ListView.builder(itemCount :  snapshot.data.length,
         itemBuilder: (context, index) {
             return Text(snpshot.data[index].toString());
});
return CicularProgressIndicator();
}
)

这是在 Flutter 的 UI 中使用期货的更推荐方式。

【讨论】:

    【解决方案2】:

    从数据库读取是一个异步活动,这意味着查询不会立即返回一些数据。所以你必须等待操作完成,然后将其分配给一个变量。

    DBProvider.instance.openDB(globalConstants.dbName);
    List<Map> list = await ObjectRepository.instance.select(DBProvider.instance.database, 'tCars') as List<Map>;
    

    另一方面,您不能在initState 中使用await。 解决方案是创建一个async 函数来处理从数据库获取数据的过程。

    Future<List<Map>> initDB()async{
      DBProvider.instance.openDB(globalConstants.dbName);
      List<Map> list = await ObjectRepository.instance.select(DBProvider.instance.database, 'tCars') as List<Map>;
      return list;
    }
    

    你终于可以在initState中调用initDB

    【讨论】:

    • 另一方面,您不能在 initState 中使用 await。解决方案是创建一个异步函数来处理从数据库获取数据的过程。最后,您可以在 initState 中调用 initDB 这对我有用:简单,对像我这样的新手有效。谢谢!
    猜你喜欢
    • 2020-06-01
    • 2020-10-24
    • 1970-01-01
    • 2021-10-08
    • 2021-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-05
    相关资源
    最近更新 更多