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

Flutter SQLite报错Unsupported operation: read-only,如何在FutureBuilder中移除列表项

解决Flutter SQLite组队功能中的"Unsupported operation: read-only"错误

问题根源

从SQLite查询返回的列表默认是不可变的(框架会用List.unmodifiable包装查询结果),直接调用removeWhere这类修改方法自然会触发"read-only"错误。另外你直接在FutureBuilder的builder回调里给allplayer赋值,每次setState都会重新执行builder,之前对列表的修改会被覆盖,还会引发状态不一致。

修复步骤

  1. 将查询结果转为可变列表:拿到snapshot.data后,用List.from()或toList()转成可修改的列表
  2. 把allplayer设为状态变量:在组件的initState或第一次拿到数据时初始化,避免每次builder重新赋值
  3. 优化组队逻辑:避免直接操作原列表时的索引越界,同步更新选择状态数组checks

修改后的完整代码示例

// 组件类中声明状态变量
late List<Map<String, dynamic>> allplayer;
late List<bool> checks;
List<String> team1 = [];
List<String> team2 = [];
bool enable = true;
String teamname = 'team 1';
final Future readdata; // 你的SQLite查询Future
bool _initialized = false; // 标记是否完成初始化

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

// FutureBuilder部分
FutureBuilder(
  future: readdata,
  builder: (BuildContext context, AsyncSnapshot snapshot) {
    if (snapshot.hasData) {
      // 仅第一次拿到数据时初始化可变列表和选择状态
      if (!_initialized) {
        allplayer = List.from(snapshot.data); // 转为可变列表
        checks = List.filled(allplayer.length, false);
        _initialized = true;
      }
      
      return ListView.builder(
        scrollDirection: Axis.vertical,
        shrinkWrap: true,
        itemCount: allplayer.length,
        itemBuilder: (BuildContext context, int i) {
          return enable 
              ? Card(
                  child: CheckboxListTile(
                    title: Text(allplayer[i]['name']),
                    value: checks[i],
                    onChanged: (value) {
                      setState(() {
                        if (value == true) {
                          team1.add(allplayer[i]['name']);

                          if (team1.length >= 2) {
                            final removeNames = [...team1];
                            // 从可变列表移除选中玩家
                            allplayer.removeWhere((element) => removeNames.contains(element['name']));
                            // 同步更新选择状态数组
                            checks = checks.where((_, idx) => !removeNames.contains(allplayer[idx]['name'])).toList();
                            teamname = 'team 2';
                            enable = false;
                            team1.clear();
                          }
                        } else if (value == false) {
                          team1.removeWhere((element) => element == allplayer[i]['name']);
                        }
                        checks[i] = value!;
                      });
                    },
                  ),
                )
              : Card(
                  child: CheckboxListTile(
                    title: Text(allplayer[i]['name']),
                    value: checks[i],
                    onChanged: (value) {
                      setState(() {
                        if (value == true) {
                          team2.add(allplayer[i]['name']);
                        } else if (value == false) {
                          team2.removeWhere((element) => element == allplayer[i]['name']);
                        }
                        checks[i] = value!;
                      });
                    },
                  ),
                );
        },
      );
    }
    return const Center(child: CircularProgressIndicator());
  },
)

额外说明

  • 新增_initialized状态变量,确保allplayer和checks只在第一次拿到数据时初始化,避免每次setState被重置
  • 用List.from(snapshot.data)将不可变列表转为可变列表,解决只读错误
  • 移除玩家时同步更新checks数组,避免ListView的索引和选择状态不匹配
  • 凑够2人后清空team1,防止后续重复处理

内容的提问来源于stack exchange,提问作者Yous y

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 07:52:52