You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

构建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层只负责监听状态变化:

  1. 首先修改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() {
    // 你的打印逻辑
  }
}
  1. 然后你的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 12:12:38