构建GridView列表时sqflite持久化数据引发类型不匹配错误
解决Future无法赋值给int的问题
嘿,我来帮你搞定这个报错!你遇到的问题很明确:playerCount是一个Future<int>类型,但GridView.builder的itemCount参数需要的是一个直接的int值,异步的Future不能直接被同步的UI组件使用,这就是报错的根源。
下面给你两种可行的解决思路,你可以根据自己的代码结构选择:
方案1:用FutureBuilder包裹GridView(快速适配现有代码)
既然playerCount是异步获取的,咱们可以用Flutter提供的FutureBuilder来等待异步操作完成,再渲染GridView。修改你的PlayerList组件:
class PlayerList extends StatelessWidget { @override Widget build(BuildContext context) { return Consumer<PlayerData>( builder: (context, playerData, child) { return FutureBuilder<int>( // 传入异步的playerCount方法 future: playerData.playerCount, // 初始状态显示0个item initialData: 0, builder: (context, snapshot) { // 处理不同的异步状态 if (snapshot.connectionState == ConnectionState.waiting) { // 加载中显示转圈指示器 return Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { // 加载失败显示错误提示 return Center(child: Text('加载玩家列表失败: ${snapshot.error}')); } else { // 拿到正确的数量后渲染GridView final count = snapshot.data ?? 0; return GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, mainAxisSpacing: 20, crossAxisSpacing: 20, ), itemCount: count, itemBuilder: (BuildContext context, int index) { final player = playerData.players[index]; return RawMaterialButton( fillColor: Color(0x991c5597), elevation: 20, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), child: Padding( padding: const EdgeInsets.all(10.0), child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ CircleAvatar( backgroundColor: Colors.tealAccent, radius: 30, child: Icon( Icons.star, color: Color(0xFF16377a), size: 30, ), ), Text(player.name, style: smallTitleText), ], ), ), onPressed: () { playerData.makeActive(player.name); playerData.printList(); Navigator.pushNamed(context, PlayScreen.id); }, ); }, ); } }, ); }, ); } }
方案2:在PlayerData中处理异步逻辑(更优雅的架构)
这种方案更符合状态管理的思路,把异步数据加载的逻辑放到PlayerData内部,让UI层只负责监听状态变化:
- 首先修改
PlayerData类,维护一个普通的int类型的_playerCount,在初始化时加载数据并更新状态:
class PlayerData extends ChangeNotifier { int _playerCount = 0; List<Player> _players = []; // 对外暴露普通的int类型 int get playerCount => _playerCount; List<Player> get players => _players; // 构造方法中自动加载数据 PlayerData() { _loadPlayersFromDB(); } Future<void> _loadPlayersFromDB() async { final Database db = await getDBConnector(); final List<Map<String, dynamic>> maps = await db.query('players'); // 把数据库返回的Map转换成Player对象(需要你给Player类实现fromMap构造方法) _players = maps.map((map) => Player.fromMap(map)).toList(); _playerCount = _players.length; // 通知UI组件更新 notifyListeners(); } // 你的其他方法保持不变 void makeActive(String name) { // 你的业务逻辑 notifyListeners(); } void printList() { // 你的打印逻辑 } }
- 然后你的
PlayerList就可以回到原来的写法,直接使用playerData.playerCount即可,因为它现在是一个普通的int值了:
class PlayerList extends StatelessWidget { @override Widget build(BuildContext context) { return Consumer<PlayerData>( builder: (context, playerData, child) { // 如果数据还没加载完,可以加个判断显示加载状态 if (playerData.playerCount == 0 && playerData.players.isEmpty) { return Center(child: CircularProgressIndicator()); } return GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, mainAxisSpacing: 20, crossAxisSpacing: 20, ), itemCount: playerData.playerCount, itemBuilder: (BuildContext context, int index) { final player = playerData.players[index]; return RawMaterialButton( // 你的按钮代码不变... onPressed: () { playerData.makeActive(player.name); playerData.printList(); Navigator.pushNamed(context, PlayScreen.id); }, ); }, ); }, ); } }
小提示
如果你选择方案2,记得给Player类添加一个fromMap构造方法,用来把数据库返回的Map转换成Player对象,比如:
class Player { final String name; // 其他属性... Player({required this.name}); // 从Map构造Player Player.fromMap(Map<String, dynamic> map) : name = map['name']; }
内容的提问来源于stack exchange,提问作者MargotB
相关产品推荐
相关产品推荐

