我正在尝试使用自定义辅助函数和抽象类在 Flutter 应用程序中抽象我的 Hive 框打开逻辑,但在传递类型时遇到问题。非抽象的、冗长的代码可以工作,但我的抽象方法失败了。如何正确地将类型传递给我的抽象辅助函数?
在所有其他地方,我一直用它们的类型显式调用 Hive 框,例如 Hive.openBox(),这工作得很好。但是,我正在尝试重构我的代码以使其更加动态并避免重复。
为什么我会遇到这个问题?我尝试了多种类型检查和不同的方法,但似乎没有任何效果。任何有关如何正确实现这种抽象的指导将不胜感激。
我创建了一个最小的可重现示例,其中包含两个简单的自定义类来提供配置单元,它导致与我的大型项目完全相同的问题:
失败示例:
abstract class HiveDB {
static Future<Box<dynamic>> secureEncryptedBox(
dynamic object, {
required String boxName,
}) async {
const secureStorage = FlutterSecureStorage();
// if key not exists return null
final encryptionKeyString = await secureStorage.read(key: 'key');
if (encryptionKeyString == null) {
final key = Hive.generateSecureKey();
await secureStorage.write(
key: 'key',
value: base64UrlEncode(key),
);
}
final key = await secureStorage.read(key: 'key');
final encryptionKeyUint8List = base64Url.decode(key!);
// Check if the box is already open, and open it with the correct type
if (Hive.isBoxOpen(boxName)) {
return TypeFilter.openHiveBoxExplicitly(object, boxName, encryptionKeyUint8List);
}
return TypeFilter.openHiveBoxExplicitlyAlternate(object, boxName, encryptionKeyUint8List);
}
}
void main() async {
await Hive.initFlutter();
Hive.registerAdapter(UserAdapter());
Hive.registerAdapter(ItemAdapter());
await Hive.openBox('secureStorage'); // This box is used for secure keys
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future<void> _saveData() async {
final user = User(name: 'John Doe', age: 30);
final item = Item(description: 'Sample Item', price: 19.99);
Box<dynamic> userBox = await HiveDB.secureEncryptedBox(user, boxName: 'user_box');
Box<dynamic> itemBox = await HiveDB.secureEncryptedBox(item, boxName: 'item_box');
userBox.add(user);
itemBox.add(item);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hive Example'),
),
body: Center(
child: ElevatedButton(
onPressed: _saveData,
child: Text('Save Data'),
),
),
);
}
}
// Abstract class TypeFilter
abstract class TypeFilter {
static Future<Box<dynamic>> openHiveBoxExplicitly<T>(
Type object,
String boxName,
List<int> encryptionKey,
) async {
Box<dynamic> encryptedBox;
if (object == User) {
encryptedBox = await Hive.openBox<User>(
boxName,
encryptionCipher: HiveAesCipher(encryptionKey),
);
} else if (object == Item) {
encryptedBox = await Hive.openBox<Item>(
boxName,
encryptionCipher: HiveAesCipher(encryptionKey),
);
} else {
throw Exception("Unknown object type");
}
return encryptedBox;
}
static Future<Box<dynamic>> openHiveBoxExplicitlyAlternate(
Type object,
String boxName,
List<int> encryptionKey,
) async {
late Box<dynamic> encryptedBox;
switch (object) {
case User:
encryptedBox = await Hive.openBox<User>(
boxName,
encryptionCipher: HiveAesCipher(encryptionKey),
);
break;
case Item:
encryptedBox = await Hive.openBox<Item>(
boxName,
encryptionCipher: HiveAesCipher(encryptionKey),
);
break;
default:
throw Exception("Unknown object type");
}
return encryptedBox;
}
}
错误:
[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: type 'User' is not a subtype of type 'Type'
#0 HiveDB.secureEncryptedBox
main.dart:30
<asynchronous suspension>
#1 _MyHomePageState._saveData
main.dart:61
<asynchronous suspension>
工作非抽象 HIVE 数据库代码:
note - 在我的实际项目中,我有一个巨大的 if 和 switch ,因为我有超过 15 个类,我试图抽象成这个方法。另外,作为信息,在我的主项目中,我需要带有“is”运算符的 if 语句以及带有对象切换的开关。为什么我不知道,这就是结果。我尝试使用 Reflectable 但没有运气,认为这可以解决这个问题。在我的主项目中,对象开关似乎在初始化应用程序时起作用,并且在保存在不同的配置中时,“is”运算符起作用,因为只有在保存或执行实际操作时我才传递实际对象。尽管如此,这里也有同样的问题,所以我做错了什么或者某个地方有问题......
abstract class HiveDB {
static Future<Box<dynamic>> secureEncryptedBox(
dynamic object, {
required String boxName,
}) async {
const secureStorage = FlutterSecureStorage();
// if key not exists return null
final encryptionKeyString = await secureStorage.read(key: 'key');
if (encryptionKeyString == null) {
final key = Hive.generateSecureKey();
await secureStorage.write(
key: 'key',
value: base64UrlEncode(key),
);
}
final key = await secureStorage.read(key: 'key');
final encryptionKeyUint8List = base64Url.decode(key!);
late Box<dynamic> encryptedBox;
// Check if the box is already open, and open it with the correct type
if (Hive.isBoxOpen(boxName)) {
if (object is User) {
encryptedBox = await Hive.openBox<User>(
boxName,
encryptionCipher: HiveAesCipher(encryptionKeyUint8List),
);
} else if (object is Item) {
encryptedBox = await Hive.openBox<Item>(
boxName,
encryptionCipher: HiveAesCipher(encryptionKeyUint8List),
);
}
} else {
// Open the box with the correct type if not already open
switch (object.runtimeType) {
case User:
encryptedBox = await Hive.openBox<User>(
boxName,
encryptionCipher: HiveAesCipher(encryptionKeyUint8List),
);
break;
case Item:
encryptedBox = await Hive.openBox<Item>(
boxName,
encryptionCipher: HiveAesCipher(encryptionKeyUint8List),
);
break;
default:
throw Exception("Unknown object type");
}
}
log(encryptedBox.runtimeType.toString());
return encryptedBox;
}
}
项目:
import 'package:hive/hive.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
part 'item.g.dart';
@HiveType(typeId: 1)
class Item {
@HiveField(0)
final String description;
@HiveField(1)
final double price;
Item({required this.description, required this.price});
}
用户:
// user.dart
import 'package:hive/hive.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
part 'user.g.dart';
@HiveType(typeId: 0)
class User {
@HiveField(0)
final String name;
@HiveField(1)
final int age;
User({required this.name, required this.age});
}
TypeFilter.openHiveBox明确第一个参数需要Type。但在 HiveDB.secureEncryptedBox 中, 使用 TypeFilter.openHiveBoxExplicitly(object, boxName, cryptoKeyUint8List) 调用;当 HiveDB.secureEncryptedBox(user, boxName: 'user_box') 时,对象类型为 User; 用户不是类型的子类型;
因此您可以显式声明 TypeFilter.openHiveBox
static Future<Box<dynamic>> openHiveBoxExplicitly<T>(
T object,
String boxName,
List<int> encryptionKey,
) async {
if (object is User) {
encryptedBox = await Hive.openBox<User>(
boxName,
encryptionCipher: HiveAesCipher(encryptionKey),
);
} else if (object is Item) {
encryptedBox = await Hive.openBox<Item>(
boxName,
encryptionCipher: HiveAesCipher(encryptionKey),
);
} else {
throw Exception("Unknown object type");
}
return encryptedBox;
}