Flutter(SQFlite) Bool转Int类型转换错误排查求助
问题背景
我是Flutter和SQFlite纯新手,为实现日历事件在应用重启后持久化,搭建SQFlite数据库时反复碰到类型转换错误,用AI调试也未能解决。错误提示:
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'bool' is not a subtype of type 'int' in type cast
报错栈指向EventHandler.fromJson等位置。
错误调用栈
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'bool' is not a subtype of type 'int' in type cast E/flutter ( 6428): #0 EventHandler.fromJson event_info_model.dart:57 E/flutter ( 6428): #1 EventsDatabase.readAllEvents.<anonymous closure> events_database.dart:95 E/flutter ( 6428): #2 MappedListIterable.elementAt (dart:_internal/iterable.dart:415:31) E/flutter ( 6428): #3 ListIterator.moveNext (dart:_internal/iterable.dart:344:26) E/flutter ( 6428): #4 new _GrowableList._ofEfficientLengthIterable (dart:core-patch/growable_array.dart:189:27) E/flutter ( 6428): #5 new _GrowableList.of (dart:core-patch/growable_array.dart:150:28) E/flutter ( 6428): #6 new List.of (dart:core-patch/array_patch.dart:47:28) E/flutter ( 6428): #7 ListIterable.toList (dart:_internal/iterable.dart:214:7) E/flutter ( 6428): #8 EventsDatabase.readAllEvents events_database.dart:96 E/flutter ( 6428): <asynchronous suspension> E/flutter ( 6428): #9 _CalendarViewPageState.refreshEvents calendar_view_page.dart:54 E/flutter ( 6428): <asynchronous suspension>
数据库代码
class EventsDatabase { static final EventsDatabase instance = EventsDatabase._init(); static Database? _database; EventsDatabase._init(); Future<Database> get database async { debugPrint("Getting database..."); if (_database != null) return _database!; _database = await _initDB('events.db'); return _database!; } Future<Database> _initDB(String filePath) async { final dbPath = await getDatabasesPath(); final path = join(dbPath, filePath); debugPrint("Database initialized. It is present at: $dbPath"); return await openDatabase(path, version: 1, onCreate: _createDB); } Future _createDB(Database db, int version) async { final textType = 'TEXT NOT NULL'; final integerType = 'INTEGER NOT NULL'; final booleanType = 'INTEGER DEFAULT 0'; await db.execute(''' CREATE TABLE $eventsTable ( 'summary' $textType, 'description' $textType, 'startTime' $integerType, 'endTime' $integerType, 'isAllDay' $booleanType ) '''); } Future<void> create(NeatCleanCalendarEvent event) async { debugPrint("The create function has been entered."); final db = await instance.database; await db.insert(eventsTable, EventHandler().toJson(event)); debugPrint(EventsDatabase.instance.toString()); debugPrint("The create function has been exited."); } Future<NeatCleanCalendarEvent?> readEvent( String summary, DateTime startTime) async { final db = await instance.database; final maps = await db.query( eventsTable, columns: EventFields.values, where: 'summary = ? AND startTime = ?', whereArgs: [summary, startTime], ); if (maps.isNotEmpty) { final map = maps.first; final modifiedMap = Map<String, Object?>.from(map); modifiedMap['isAllDay'] = (map['isAllDay'] == 1 ? true : false); // Convert to boolean return EventHandler.fromJson(modifiedMap); } else { return null; // Return null if no matching event is found } } Future<List<NeatCleanCalendarEvent>> readAllEvents() async { final db = await instance.database; final orderBy = 'startTime ASC'; final result = await db.query( eventsTable, orderBy: orderBy, ); return result.map((json) { final modifiedJson = Map<String, Object?>.from(json); modifiedJson['isAllDay'] = (json['isAllDay'] == 1 ? true : false); // Convert to boolean return EventHandler.fromJson(modifiedJson); }).toList(); } Future<int> update(NeatCleanCalendarEvent event) async { debugPrint("The update function has been entered."); final db = await instance.database; return db.update( eventsTable, EventHandler().toJson(event), where: 'summary = ? AND startTime = ?', whereArgs: [event.summary, event.startTime], ); } Future<int> delete(NeatCleanCalendarEvent event) async { debugPrint("The delete function has been entered."); final db = await instance.database; return await db.delete( eventsTable, where: 'summary = ? AND startTime = ?', whereArgs: [event.summary, event.startTime], ); } Future<void> close() async { debugPrint("The close function has been entered."); final db = await instance.database; await db.close(); } }
EventHandler类代码
final String eventsTable = 'events'; class EventFields { static final List<String> values = [ summary, description, startTime, endTime, isAllDay ]; static final String summary = 'summary'; static final String description = 'description'; static final String startTime = 'startTime'; static final String endTime = 'endTime'; static final String isAllDay = 'isAllDay'; // Add this line for the new field } class EventHandler { Map<String, Object?> toJson(NeatCleanCalendarEvent event) => { EventFields.summary: event.summary, EventFields.description: event.description, EventFields.startTime: event.startTime.millisecondsSinceEpoch, EventFields.endTime: event.endTime.millisecondsSinceEpoch, EventFields.isAllDay: event.isAllDay ? 1 : 0, // Convert to integer }; static NeatCleanCalendarEvent fromJson(Map<String, Object?> json) => NeatCleanCalendarEvent( json[EventFields.summary] as String, description: json[EventFields.description] as String, startTime: DateTime.fromMillisecondsSinceEpoch( json[EventFields.startTime] as int), endTime: DateTime.fromMillisecondsSinceEpoch( json[EventFields.endTime] as int), isAllDay: (json[EventFields.isAllDay] as int) == 1, // Convert to boolean ); }
问题原因与解决方法
核心问题
在readEvent和readAllEvents方法中,你将从数据库读取的isAllDay字段(原本是int类型的0或1)转换成了bool值,随后将这个bool值传入EventHandler.fromJson方法,但该方法仍尝试把json[EventFields.isAllDay]当作int强转,导致类型不匹配错误。
修复方案
有两种可行的修复方式:
方式一:修改fromJson方法,兼容int和bool类型
直接在fromJson中处理isAllDay的类型判断,不管传入的是int还是bool都能正确转换:
static NeatCleanCalendarEvent fromJson(Map<String, Object?> json) => NeatCleanCalendarEvent( json[EventFields.summary] as String, description: json[EventFields.description] as String, startTime: DateTime.fromMillisecondsSinceEpoch( json[EventFields.startTime] as int), endTime: DateTime.fromMillisecondsSinceEpoch( json[EventFields.endTime] as int), isAllDay: json[EventFields.isAllDay] is bool ? json[EventFields.isAllDay] as bool : (json[EventFields.isAllDay] as int) == 1, );
方式二:移除读取时的bool转换,让fromJson直接处理数据库返回的int值
删掉readEvent和readAllEvents里的modifiedJson['isAllDay']转换逻辑,让fromJson直接处理数据库返回的int类型值:
- 修复后的
readEvent方法:
Future<NeatCleanCalendarEvent?> readEvent( String summary, DateTime startTime) async { final db = await instance.database; final maps = await db.query( eventsTable, columns: EventFields.values, where: 'summary = ? AND startTime = ?', whereArgs: [summary, startTime.millisecondsSinceEpoch], // 传入时间戳而非DateTime对象 ); if (maps.isNotEmpty) { return EventHandler.fromJson(maps.first); } else { return null; } }
- 修复后的
readAllEvents方法:
Future<List<NeatCleanCalendarEvent>> readAllEvents() async { final db = await instance.database; final orderBy = 'startTime ASC'; final result = await db.query( eventsTable, orderBy: orderBy, ); return result.map((json) => EventHandler.fromJson(json)).toList(); }
注意:
readEvent里的whereArgs原本传入的是startTime(DateTime对象),但数据库里存的是时间戳int,所以需要改成startTime.millisecondsSinceEpoch,否则查询不到数据。
额外建议
- 数据库版本更新:如果之前已经创建过表,修改代码后需要升级数据库版本(把
openDatabase里的version从1改成2),或者卸载重装APP,避免旧表结构导致的问题。 - 类型安全:尽量保持数据在序列化/反序列化时的类型一致,减少中间转换步骤,避免类似的类型错误。
内容的提问来源于stack exchange,提问作者Nandan Praveen

