Я делаю приложение календаря / планировщика для android, используя Dart / Flutter. Приложение отлично работает при первом запуске, но если я закрою приложение в эмуляторе и снова открою, оно выдаст ошибку. Однако приложение снова начнет работать, если я перезапущу его с помощью функций запуска / отладки в коде Visual Studio. Также, если для устранения неполадок требуется больше стека, просто ответьте в комментариях, и я выложу все, что нужно.
Мой код выглядит следующим образом:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:table_calendar/table_calendar.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Calendar',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
CalendarController _controller;
Map<DateTime, List<dynamic>> _events;
List<dynamic> _selectedEvents;
TextEditingController _eventController;
SharedPreferences prefs;
@override
void initState() {
super.initState();
_controller = CalendarController();
_eventController = TextEditingController();
_events = {};
_selectedEvents = [];
initPrefs();
}
initPrefs() async {
prefs = await SharedPreferences.getInstance();
setState(() {
_events = Map<DateTime, List<dynamic>>.from(
decodeMap(json.decode(prefs.getString("events") ?? "{}"))
);
});
}
Map<String, dynamic> encodeMap(Map<DateTime, dynamic> map) {
Map<String, dynamic> newMap = {};
map.forEach((key, value) {
newMap[key.toString()] = map[key];
});
return newMap;
}
Map<DateTime, dynamic> decodeMap(Map<String, dynamic> map) {
Map<DateTime, dynamic> newMap = {};
map.forEach((key, value) {
newMap[DateTime.parse(key)] = map[key];
});
return newMap;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Calendar'),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TableCalendar(
events: _events,
initialCalendarFormat: CalendarFormat.week,
calendarStyle: CalendarStyle(
canEventMarkersOverflow: true,
todayColor: Colors.orange,
selectedColor: Theme.of(context).primaryColor,
todayStyle: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Colors.white
)
),
headerStyle: HeaderStyle(
centerHeaderTitle: true,
formatButtonDecoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(20.0),
),
formatButtonTextStyle: TextStyle(color: Colors.white),
formatButtonShowsNext: false,
),
startingDayOfWeek: StartingDayOfWeek.sunday,
onDaySelected: (date, events) {
setState(() {
_selectedEvents = events;
});
},
builders: CalendarBuilders(
selectedDayBuilder: (context, date, events) => Container(
margin: const EdgeInsets.all(4.0),
alignment: Alignment.center,
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(10.0)
),
child: Text(
date.day.toString(),
style: TextStyle(color: Colors.white),
)
),
todayDayBuilder: (context, date, events) => Container(
margin: const EdgeInsets.all(4.0),
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(10.0)
),
child: Text(
date.day.toString(),
style: TextStyle(color: Colors.white),
)
),
),
calendarController: _controller,
),
..._selectedEvents.map((event) => ListTile(
title: Text(event),
)),
],
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: _showAddDialog,
),
);
}
_showAddDialog() async {
await showDialog(
context: context,
builder: (context) => AlertDialog(
content: TextField(
controller: _eventController,
),
actions: <Widget>[
FlatButton(
child: Text("Save"),
onPressed: () {
if (_eventController.text.isEmpty) return;
if (_events[_controller.selectedDay] != null) {
_events[_controller.selectedDay].add(_eventController.text);
} else {
_events[_controller.selectedDay] = [
_eventController.text
];
}
prefs.setString("events", json.encode(encodeMap(_events)));
_eventController.clear();
Navigator.pop(context);
},
)
],
)
);
setState(() {
_selectedEvents = _events[_controller.selectedDay];
});
}
}
и сообщение об ошибке, которое я получаю, когда Я закрываю приложение и заново открываю его в эмуляторе так:
I/flutter (16166): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (16166): The following assertion was thrown building HomePage(dirty, dependencies:
I/flutter (16166): [_LocalizationsScope-[GlobalKey#10869], _InheritedTheme], state: _HomePageState#1aa67):
I/flutter (16166): setState() or markNeedsBuild() called during build.
I/flutter (16166): This Overlay widget cannot be marked as needing to build because the framework is already in the
I/flutter (16166): process of building widgets. A widget can be marked as needing to be built during the build phase
I/flutter (16166): only if one of its ancestors is currently building. This exception is allowed because the framework
I/flutter (16166): builds parent widgets before children, which means a dirty descendant will always be built.
I/flutter (16166): Otherwise, the framework might not visit this widget during this build phase.
I/flutter (16166): The widget on which setState() or markNeedsBuild() was called was:
I/flutter (16166): Overlay-[LabeledGlobalKey<OverlayState>#81c4c]
I/flutter (16166): The widget which was currently being built when the offending call was made was:
I/flutter (16166): HomePage
I/flutter (16166):
I/flutter (16166): The relevant error-causing widget was:
I/flutter (16166): HomePage
package:hello_world/main.dart:15
I/flutter (16166):
I/flutter (16166): When the exception was thrown, this was the stack:
I/flutter (16166): #0 Element.markNeedsBuild.<anonymous closure>
package:flutter/…/widgets/framework.dart:3896
I/flutter (16166): #1 Element.markNeedsBuild
package:flutter/…/widgets/framework.dart:3911
I/flutter (16166): #2 State.setState
package:flutter/…/widgets/framework.dart:1168
I/flutter (16166): #3 OverlayState.insertAll
package:flutter/…/widgets/overlay.dart:344
I/flutter (16166): #4 OverlayRoute.install
package:flutter/…/widgets/routes.dart:44
I/flutter (16166): #5 TransitionRoute.install
package:flutter/…/widgets/routes.dart:181
I/flutter (16166): #6 ModalRoute.install
package:flutter/…/widgets/routes.dart:959
I/flutter (16166): #7 NavigatorState.push
package:flutter/…/widgets/navigator.dart:1791
I/flutter (16166): #8 showGeneralDialog
package:flutter/…/widgets/routes.dart:1634
I/flutter (16166): #9 showDialog
package:flutter/…/material/dialog.dart:711
I/flutter (16166): #10 _HomePageState._showAddDialog
package:hello_world/main.dart:90