Flutter Unhandled Exception: Concurrent modification during iteration: Instance(length:3) of ‘_Growa

【Flutter错误锦囊】

在Flutter开发中遇到的异常ConcurrentModificationException,是发生在使用List集合数据时的情况,因操作不合理而抛出的异常,通常异常日志如下:

E/flutter (15758): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: Concurrent modification during iteration: Instance(length:3) of '_GrowableList'.
E/flutter (15758): #0      ListIterator.moveNext (dart:_internal/iterable.dart:340:7)
E/flutter (15758): #1      SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1012:44)
E/flutter (15758): #2      SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:929:5)
E/flutter (15758): #3      _rootRun (dart:async/zone.dart:1184:13)
E/flutter (15758): #4      _CustomZone.run (dart:async/zone.dart:1077:19)
E/flutter (15758): #5      _CustomZone.runGuarded (dart:async/zone.dart:979:7)
E/flutter (15758): #6      _invoke (dart:ui/hooks.dart:261:10)
E/flutter (15758): #7      _drawFrame (dart:ui/hooks.dart:219:3)

1 情景一 遍历list集合时删除元素出现的异常

代码如下:

List list = [...];
for (int i = 0; i < list.length; i++) {
  if(...){
     list.remove(...)
  }
}

解决方案一 是新创建一个集合然后将符合条件的数据保存到新的集合中,然后遍历结束后使用新的集合数据,代码如下:

///原数据集合
List list = [...];
///临时的空集合
List themList =[];

///清空临时集合
themList.clear();

for (int i = 0; i < list.length; i++) {
  ///将符合条件的数据添加到临时集合中
  if(...){
     themList.add();
  }
}
///重新赋值
list = themList;

解决方案二 :使用Dar提供的循环并删除的方法

for (int i = 0; i < list.length; i++) {
  ///将符合条件的数据添加到临时集合中
  if(...){
      // 使用箭头函数,后面的表达式为true时会删除当前值
      list.removeWhere((value) => value == 2); 
      // 或者使用
      list.removeWhere((value) {
      retrun value == 2;
      });
  }
}

2 情景二 使用 WidgetsBinding添加addPersistentFrameCallback出现的Concurrent modification 异常

在Flutter开发中通常通过 WidgetsBinding 添加 一个页面实时绘制Frame的回调兼听,一般放在初始化 initState 函数中。

   WidgetsBinding.instance.addPersistentFrameCallback((Duration timeStamp){
      debugPrint(" 生命周期 实时 Frame 绘制回调"); //  每帧都回调
    });

当兼听的页面中有初始化的List数据时,会出现此异常,解决方法是在页面的第一帧绘制完成后再添加这个兼听:

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


    WidgetsBinding.instance.addObserver(this);

    ///单次 Frame 绘制回调,通过 addPostFrameCallback 实现。
    ///它会在当前 Frame 绘制完成后进行回调,并只会回调一次,如果要再次监听则需要再设置一次。
    WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp){
      debugPrint(" 生命周期 单次 Frame 绘制回调"); // 只回调一次
      ///在第一次绘制完成时再添加实时回调的监听
      addPersistentFrameCallbackFunction();


    });
  
  }

  ///在页面的每帧绘制完成后添加的实时
  void addPersistentFrameCallbackFunction(){
    ///实时 Frame 绘制回调,则通过 addPersistentFrameCallback 实现。
    ///这个函数会在每次绘制 Frame 结束后进行回调,可以用作 FPS 检测。
    WidgetsBinding.instance.addPersistentFrameCallback((Duration timeStamp){
      debugPrint(" 生命周期 实时 Frame 绘制回调"); //  每帧都回调
    });
  }

公众号 我的大前端生涯

早起的年轻人 CSDN认证博客专家 移动开发 项目管理 Java
只要用心去做,每一件事情还是有可能成功的,当然成功是没有界限的,只不过是达到自己心里的那个目标,公众号:我的大前端生涯,一个爱喝茶的程序员,通常会搞搞SpringBoot 、Herbinate、Mybatiys、Android、iOS、Flutter、Vue、小程序等.
©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页