You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter(SQFlite) Bool转Int类型转换错误排查求助

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 17:14:56