dart Flutter Hive向后兼容性

woobm2wo  于 2024-01-04  发布在  Flutter
关注(0)|答案(1)|浏览(141)

我正在使用hive进行本地缓存。
在这个应用程序中,我有一个名为user的配置单元对象。

class UserModel extends HiveObject implements Copyable<UserModel> {

UserModel({
required this.id,
required this.name,
});

  @HiveField(0)
  String id;
  @HiveField(1)
  String name;
  
factory UserModel.fromJson(Map<String,dynamic> json) => UserModel(
id: json['id'],
name: json['name']
);
}

class UserModelAdapter extends TypeAdapter<UserModel> {
  @override
  final typeId = 1;

  @override
  UserModel read(BinaryReader reader) {
    var numOfFields = reader.readByte();
    var fields = <int, dynamic>{
      for (var i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };

return UserModel(
id: fields[0] as String,
name: fields[1] as String,
);
}
@override
void write (BinaryWriter writer, UserModel obj){

writer
 ..writeByte(2)
 ..writeByte(0)
 ..write(obj.id)
 ..writeByte(1)
 ..write(obj.name)
  }
 }
}

字符串
上面的用户模型是应用程序的一部分,现在已经上线了,它的工作和预期的一样。

class UserModel extends HiveObject implements Copyable<UserModel> {

UserModel({
required this.id,
required this.name,
required this.favourite
});

  @HiveField(0)
  String id;
  @HiveField(1)
  String name; 
  @HiveField(2)
  List<String> favourite
  
factory UserModel.fromJson(Map<String,dynamic> json) => UserModel(
id: json['id'],
name: json['name'],
favourite :  List<String>.from(
          json["favourite"] ?? [].map((x) => x))
 );
}

class UserModelAdapter extends TypeAdapter<UserModel> {
  @override
  final typeId = 1;

  @override
  UserModel read(BinaryReader reader) {
    var numOfFields = reader.readByte();
    var fields = <int, dynamic>{
      for (var i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };

return UserModel(
id: fields[0] as String,
name: fields[1] as String,
favourite: fields[2] as List<String>
);
}
@override
void write (BinaryWriter writer, UserModel obj){

writer
 ..writeByte(3)
 ..writeByte(0)
 ..write(obj.id)
 ..writeByte(1)
 ..write(obj.name)
 ..writeByte(2)
 ..write(obj.favourite)
  }
 }
}


然而,在通过添加新字段更新如上所示的用户对象后,新版本的应用程序会因类型适配器抛出错误而中断。如何确保添加新字段不会中断应用程序?

c9qzyr3d

c9qzyr3d1#

我不确定这对你是否有用,但是对于这个问题的新手来说,hive_generator版本1.1.0和更高版本允许你传递一个命名参数defaultValue到你的@HiveField注解。
因此,对于新创建的字段,可以给予如下所示的默认值:

@HiveField(123, defaultValue: 20)
int someNewField;

字符串
如果20从该高速缓存中为空,则这将someNewField作为第一值。

自定义适配器

或者,作为第二种选择,您可以始终为您的Hive模型创建自定义适配器。这有点复杂和繁琐,但如果您来到这里寻求答案,您可能需要这种解决方案。如果字段的类型发生变化(出于某种原因),这种方法也很有用。
假设这是你的Hive模型:

// some_model.dart

part 'some_model.g.dart';

@HiveType(typeId: 1)
class SomeModel {
  SomeModel({
    required this.productionField1,
    required this.productionField2,
    required this.productionField3,
  });
  @HiveField(1)
  int productionField1;
  @HiveField(2)
  double productionField2;
  @HiveField(3)
  bool productionField3;
}


这是生成的some_model.g.dart文件:

// GENERATED CODE - DO NOT MODIFY BY HAND
// `some_model.g.dart`

part of 'some_model.dart';

// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************

class SomeModelAdapter extends TypeAdapter<SomeModel> {
  @override
  final int typeId = 1;

  @override
  SomeModel read(BinaryReader reader) {
    final numOfFields = reader.readByte();
    final fields = <int, dynamic>{
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return SomeModel(
      productionField1: fields[1] as int,
      productionField2: fields[2] as double,
      productionField3: fields[3] as bool,
    );
  }

  @override
  void write(BinaryWriter writer, SomeModel obj) {
    writer
      ..writeByte(3)
      ..writeByte(1)
      ..write(obj.productionField1)
      ..writeByte(2)
      ..write(obj.productionField2)
      ..writeByte(3)
      ..write(obj.productionField3);
  }

  @override
  int get hashCode => typeId.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is SomeModelAdapter &&
          runtimeType == other.runtimeType &&
          typeId == other.typeId;
}


如果你想将someNewField添加到这个类中,你可以像下面这样自定义类和适配器:

// some_model.dart

part 'custom_some_model_adapter.dart'; // this is now pointing your custom adapter file

@HiveType(typeId: 1)
class SomeModel {
  SomeModel({
    required this.productionField1,
    required this.productionField2,
    required this.productionField3,
    required this.someNewField,
  });
  @HiveField(1)
  int productionField1;
  @HiveField(2)
  double productionField2;
  @HiveField(3)
  bool productionField3;
  @HiveField(4)
  int someNewField;
}
// custom_some_model_adapter.dart

part of 'some_model.dart';

class CustomSomeModelAdapter extends TypeAdapter<SomeModel> {
  @override
  final int typeId = 1;

  @override
  SomeModel read(BinaryReader reader) {
    final numOfFields = reader.readByte();
    final fields = <int, dynamic>{
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return SomeModel(
      productionField1: fields[1] as int,
      productionField2: fields[2] as double,
      productionField3: fields[3] as bool,
      someNewField: fields[4] as int? ?? 100, // this, basically does what the defaultValue parameter provides
    );
  }

  @override
  void write(BinaryWriter writer, SomeModel obj) {
    writer
      ..writeByte(4)
      ..writeByte(1)
      ..write(obj.productionField1)
      ..writeByte(2)
      ..write(obj.productionField2)
      ..writeByte(3)
      ..write(obj.productionField3)
      ..writeByte(4)            // these two lines will ensure new values 
      ..write(obj.someNewField) // that are given to someNewField will persist on cache 
  }

  @override
  int get hashCode => typeId.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is CustomSomeModelAdapter &&
          runtimeType == other.runtimeType &&
          typeId == other.typeId;
}

剩下要做的就是将CustomSomeModelAdapter注册到hive:

Hive.registerAdapter<SomeModel>(CustomSomeModelAdapter());

相关问题