简体   繁体   中英

flutter Bad state: Future already completed and Failed assertion: line 2113 pos 12: '!_debugLocked': is not true

First post on this site so if there are any tips on formatting the question or not following the guidelines please let me know. Thank you

In the flutter app I am creating I am using a third party calendar widget that is nested inside a modalBottomSheet. When using Navigator.pop in the onChanged method to close the calendar widget, the following error is thrown:

'package:flutter/src/widgets/navigator.dart': Failed assertion: line 2330 pos 12: '!_debugLocked': is not true.

If I pick a day in the same month that the calendar is created, I do not get an error. The error only appears if I go backwards or forwards a month and select a date. I also get the error when I move forward (or backward) a month and then come back to the month that the calendar was created in. For example, if I use today's date as the selected date, the month is March. If I use the arrows and go back to February or forward to April and select a date, I get the above error.

The calendar package I am using is: flutter_date_pickers: ^0.0.5

I have created a minimum running example from the code below:

import 'package:flutter/material.dart';
import 'package:flutter_date_pickers/flutter_date_pickers.dart' as dp;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String date;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    date = DateTime.now().toIso8601String();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Selected Date:',
            ),
            Text(
              '$date',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _openDatePicker(context);
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }

  void _openDatePicker(BuildContext context) {
    showModalBottomSheet<DateTime>(
        context: context,
        builder: (BuildContext context) {
          return Container(
            child: dp.DayPicker(
              selectedDate: DateTime.now(),
              onChanged: (dateTime) {
                Navigator.pop(context, dateTime);
              },
              firstDate: DateTime.now().subtract(Duration(days: 360)),
              lastDate: DateTime.now().add(Duration(days: 360)),
            ),
          );
        }).then(
      (dateTime) {
        if (dateTime != null) {
          setState(() {
            date = dateTime.toIso8601String();
          });
          print('date time: ' + date);
        } else {
          print('No Day Selected');
        }
      },
    );
  }
}

I have gone through and looked at other questions with similar errors and tried all of the different methods to fix this with only one method working for me. It was to convert the Navigator.pop to a Navigator.pushNamedAndReplace method. Unfortunately in my actual app this becomes so slow that it is not realistically usable.

Any help would be appreciated. Thank you

As the print inside onChanged shows for some reason onChanged is called twice every time user selects date, this causes the overlapping of multiple Navigator.pop()s leading to debugLocked issue , what I did is simply making sure Navigator.pop() is only getting called once using a boolean variable like this

if(open)Navigator.pop(context, dateTime); open = false;

The corrected full code is as follows :

import 'package:flutter/material.dart';
import 'package:flutter_date_pickers/flutter_date_pickers.dart' as dp;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String date;
  bool open = false;


  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    date = DateTime.now().toIso8601String();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Selected Date:',
            ),
            Text(
              '$date',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _openDatePicker(context);
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }

  void _openDatePicker(BuildContext context) {
    open = true;
    showModalBottomSheet<DateTime>(
        context: context,
        builder: (BuildContext context) {
          return Container(
            child: dp.DayPicker(
              selectedDate: DateTime.now(),
              onChanged: (dateTime) {

                if(open)Navigator.pop(context, dateTime);
                open = false;

              },
              firstDate: DateTime.now().subtract(Duration(days: 360)),
              lastDate: DateTime.now().add(Duration(days: 360)),
            ),
          );
        }).then(
      (dateTime) {
        if (dateTime != null) {
          setState(() {
            date = dateTime.toIso8601String();
          });
          print('date time: ' + date);
        } else {
          print('No Day Selected');
        }
      },
    );
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM