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

Flutter Hive报错:List<dynamic>无法转为List<MessageModel>,删Hive文件可恢复

解决Hive中List<dynamic>无法转换为List<MessageModel>的TypeError

问题场景

运行代码时抛出TypeError:'type 'List<dynamic>' is not a subtype of type 'List<MessageModel>' in type cast',删除磁盘上的Hive文件后程序即可正常运行。

初始化代码

Future initHive() async {
  await Hive.initFlutter();
  if (!Hive.isAdapterRegistered(MessageEnumAdapter().typeId)) {
    Hive.registerAdapter(MessageEnumAdapter());
  }
  if (!Hive.isAdapterRegistered(UserModelAdapter().typeId)) {
    Hive.registerAdapter(UserModelAdapter());
  }
  if (!Hive.isAdapterRegistered(MessageModelAdapter().typeId)) {
    Hive.registerAdapter(MessageModelAdapter());
  }
  if (!Hive.isAdapterRegistered(ChatModelAdapter().typeId)) {
    // only register if MessageModelAdapter is already registered
    if (Hive.isAdapterRegistered(MessageModelAdapter().typeId)) {
      Hive.registerAdapter(ChatModelAdapter());
    }
  }
  // if the box is not exist, create new box
  if (!Hive.isBoxOpen(hiveChatBox)) {
    hive = await Hive.openBox<ChatModel>(hiveChatBox);
  }

  // return hive;
}

ChatModelAdapter代码

class ChatModelAdapter extends TypeAdapter<ChatModel> {
  @override
  final int typeId = 0;

  @override
  ChatModel read(BinaryReader reader) {
    return ChatModel(
      id: reader.read() as String,
      chatType: reader.read() as String,
      participants: reader.read() as List<String>,
      createdAt: reader.read() as DateTime,
      numberOfNewMessages: reader.read() as int,
      lastMessage: reader.read() as MessageModel?,
      messages: reader.read() as List<MessageModel>,
    );
  }

  @override
  void write(BinaryWriter writer, ChatModel obj) {
    writer.write(obj.id);
    writer.write(obj.chatType);
    writer.write(obj.participants);
    writer.write(obj.createdAt);
    writer.write(obj.numberOfNewMessages);
    writer.write(obj.lastMessage);
    writer.write(obj.messages);
  }
}

问题原因

本质是旧的Hive存储数据与当前适配器的类型定义不兼容。早期运行时可能MessageModelAdapter未正确注册,或者ChatModel的messages字段被序列化为List<dynamic>;后续代码明确指定类型后,Hive读取旧数据时无法直接将动态列表强转为List<MessageModel>,所以报错。删除文件清空旧数据后,新写入的数据类型匹配,自然正常运行。

解决方案

1. 兼容旧数据(无需删除文件)

修改ChatModelAdapter的read方法,手动将读取到的动态列表转换为List<MessageModel>,替换直接强制类型转换:

@override
ChatModel read(BinaryReader reader) {
  return ChatModel(
    id: reader.read() as String,
    chatType: reader.read() as String,
    participants: reader.read() as List<String>,
    createdAt: reader.read() as DateTime,
    numberOfNewMessages: reader.read() as int,
    lastMessage: reader.read() as MessageModel?,
    // 转换动态列表为强类型列表
    messages: (reader.read() as List).cast<MessageModel>(),
  );
}

2. 优化适配器注册顺序

确保依赖的适配器先注册(MessageModelAdapter必须在ChatModelAdapter之前注册),同时简化冗余的判断逻辑:

Future initHive() async {
  await Hive.initFlutter();
  
  // 按依赖顺序注册:先注册Message相关适配器
  if (!Hive.isAdapterRegistered(MessageEnumAdapter().typeId)) {
    Hive.registerAdapter(MessageEnumAdapter());
  }
  if (!Hive.isAdapterRegistered(MessageModelAdapter().typeId)) {
    Hive.registerAdapter(MessageModelAdapter());
  }
  
  // Message适配器注册完成后再注册ChatModelAdapter
  if (!Hive.isAdapterRegistered(ChatModelAdapter().typeId)) {
    Hive.registerAdapter(ChatModelAdapter());
  }
  
  // 最后注册用户模型适配器
  if (!Hive.isAdapterRegistered(UserModelAdapter().typeId)) {
    Hive.registerAdapter(UserModelAdapter());
  }

  if (!Hive.isBoxOpen(hiveChatBox)) {
    hive = await Hive.openBox<ChatModel>(hiveChatBox);
  }
}

3. 正式应用版本迁移(避免用户删文件)

如果应用已经发布,不能让用户手动删除文件,可使用Hive的迁移机制处理旧数据:

// 打开Box时指定迁移逻辑和版本号
hive = await Hive.openBox<ChatModel>(
  hiveChatBox,
  migration: (oldBox, newBox) {
    // 针对旧版本(version 0)的数据做转换
    if (oldBox.version == 0) {
      for (var key in oldBox.keys) {
        var oldChat = oldBox.get(key);
        if (oldChat != null) {
          newBox.put(
            key,
            ChatModel(
              id: oldChat.id,
              chatType: oldChat.chatType,
              participants: oldChat.participants,
              createdAt: oldChat.createdAt,
              numberOfNewMessages: oldChat.numberOfNewMessages,
              lastMessage: oldChat.lastMessage,
              messages: (oldChat.messages as List).cast<MessageModel>(),
            ),
          );
        }
      }
    }
  },
  version: 1, // 升级Box版本号,触发迁移
);

内容的提问来源于stack exchange,提问作者Yosef Schwartz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 13:52:04