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
相关产品推荐
相关产品推荐

