Flutter坏状态无元素

7

我正在尝试从数据库中删除我的数据,并在成功后导航到我的主页。

以下是我的代码:

StatelessWidget 包含了一个 deleteFromDatabase 方法,该方法传递了一个 Id(String) 和一个 context

Consumer<SettingsProvider>(
      builder: (context, settingsProvider, child) {
        final exerciseSettings = settingsProvider.findById(id);
        if (exerciseSettings == null) {
          return Center(
            child: CircularProgressIndicator(),
          );
        }
        return PreviewExerciseItem(
          exerciseSettings: exerciseSettings,
          id: id,
          navigateToEdit: () =>
              _navigateToEditPage(exerciseSettings, context),
          deleteFromDatabase: () => _deleteFromDatabase(id, context),
          navigateToCountDown: () =>
              navigateToCountDownPage(exerciseSettings, context),
        );
      },
    ),

_deleteFromDatabase方法从StatelessWidget中调用,并显示AlertDialog以确认删除:

void _deleteFromDatabase(String id, context) async {
await showDialog(
  context: context,
  builder: (context) => new AlertDialog(
    title: new Text("Are you sure you want to delete?"),
    actions: <Widget>[
      new FlatButton(
        onPressed: () => Navigator.of(context).pop(false),
        child: new Text('No'),
      ),
      new FlatButton(
        onPressed: () async {
          try {
            Navigator.of(context).pop(true);
            await Provider.of<SettingsProvider>(context, listen: false)
                .deleteFromList(id);
            Navigator
                .pushNamedAndRemoveUntil(context,HomePage.routeName, (Route route) => route.isFirst);
          } catch (e) {
            print(e);
          }
        },
        child: new Text('Yes'),
      ),
    ],
  ),
 );
}

我的提供程序类中的 deleteFromList 方法:

Future<void> deleteFromList(String id) async{
try{
  final _itemIndex = _items.indexWhere((item) => item.id == id);
  await _databaseHelper.deleteExercises(id);
  _items.removeAt(_itemIndex);
  notifyListeners();
}catch(e){
  print(e);
 }
}

Provider类中的findById:

CustomExercise findById(String id) {
  return _items.firstWhere((prod) => prod.id == id);
}

注意:我已经成功从数据库中删除了我的数据,但就在它导航到我的主页之前,一个错误会以红色屏幕的形式出现并在一瞬间消失:Bad State: No Element。
以下是来自我的日志的完整错误消息:
正在构建 Consumer(dirty, dependencies: [_InheritedProviderScope, _InheritedTheme, _LocalizationsScope-[GlobalKey#5ce12]]) 时抛出以下 StateError: 坏状态:没有元素
相关的引起错误的小部件是:
Consumer<SettingsProvider>

当异常被抛出时,这是他的调用栈:

#0 ListMixin.firstWhere (dart:collection/list.dart:150:5)

#1 SettingsProvider.findById (package:workoutapp/providers/settings_provider.dart:12:19)

#2 PreviewExercisePage.build.<anonymous closure>(package:workoutapp/pages/preview_exercise_page.dart:68:55)

#3 Consumer.buildWithChild (package:provider/src/consumer.dart:175:19)

#4 SingleChildStatelessWidget.build (package:nested/nested.dart:260:41)


7
坏的状态:当你调用一个空列表的方法并需要通过它的元素来检查值时(在这种情况下是通过调用某个列表中的firstWhere进行settingsProvider.findById(id)),就会出现没有元素的情况。您能否发帖findById方法的代码? - EdwynZN
嗨,是的,你说得对。显然因为我正在使用一个Consumer,它会不断地监听变化,因此在我删除数据后,它会接收到一个null值,而实际上它应该已经停止监听了。因此,我通过使用Provider.of<SettingsProvider>(context,listen: false)来解决我的问题,以确保它只在屏幕加载时监听一次。 - Wei Jun
1
另外补充一点,对于我的情况,错误信息只在屏幕上闪现了一瞬间,然后就导航到我的主页了,并且数据确实已经成功地从数据库中删除。所以对于我的情况,问题并不在findById函数上。但是还是感谢您之前提供的建议,让我知道之前我忽略了该函数而一直认为问题在delete函数上。 - Wei Jun
同样的问题在这里...请帮忙... https://stackoverflow.com/questions/64154373/bad-state-no-element-in-flutter-after-deleting-an-item - Athira Reddy
4个回答

11
当列表为空或第一个元素为空时,将会出现这种情况,因此您应该检查列表不为空。
List list = [];

print(list[0])

您一定会收到这样的消息:

Unhandled exception:
Bad state: No element
#0      List.first (dart:core-patch/growable_array.dart:332:5)
#1      main (file:///C:/Users/onbody/AndroidStudioProjects/nmae/bin/name.dart:9:14)
#2      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:281:32)
#3      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

解决方案是:

List list = [];

if (list.isNotEmpty) {
    print(list[0]);
  } else {
    print('the list is empty'!);
  }

我希望对某人有所帮助。谢谢!


2
如之前在评论中提到的,检查空列表的值很可能会导致错误。解决方法是在CustomExercise findById(String)deleteFromList(String)两个方法中都加入一个检查器来判断列表是否为空。
例如:
if(_items != null && _items.length > 0)

0
我们使用的是Drift(之前叫Moor)和它的watchSingle()方法。如果没有找到匹配的数据库行,它会抛出此错误。
由于流正在发出错误,并且没有堆栈跟踪附加到它上面,所以很难追踪。
修复方法是改用带有limit(1)的watch()并在结果为空时跳过处理。

0
使用orElse回调来返回CustomExercise()的实例。这样,您就不会遇到错误。
CustomExercise findById(String id) {
  return _items.firstWhere((prod) => prod.id == id,
    orElse: () => CustomExercise());
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接