我正在尝试通过实现库存应用程序来学习 Flutter。我的应用程序当前从 json 文件读取项目列表,由 Riverpod 管理,这部分有效。我还了解到 Flutter 不允许写入资产,因此我编写了一个 insertItem() 方法,该方法写入本地文件,并将新项目添加到托管的当前项目列表中。它们都没有生成,没有错误。我只看到“已添加项目”小吃栏,库存列表在库存列表屏幕中是相同的,而且文件不在本地设备文件资源管理器中。我将尝试简要添加代码的相关部分,如果希望查看其他部分,请告诉我。从 Json 资产文件部分读取效果很好。
@riverpod
class JsonInventoryService extends _$JsonInventoryService {
late Future<List<Item>> _currentItems;
late InventoryResult inventoryResult;
@override
Future<List<Item>> build() {
return Future.value([Item(id: 0, productName: 'NULL ITEM'),]);
}
Future loadItems() async {
var jsonString = await rootBundle.loadString('assets/inventorylist.json');
inventoryResult =
InventoryResult.fromJson(jsonDecode(jsonString));
_currentItems = Future.value(inventoryResultsToItems(inventoryResult));
}
Future<List<Item>> fetchData() async {
return _currentItems;
}
插入项目方法:
Map<String, dynamic> insertItem(Item item) {
inventoryResult.results.add(item);
final jsonmap = inventoryResult.toJson(); //json_serializable automatically handles nested class
storage.writeFile(jsonmap);
return jsonmap;
}
}
Inventory Result 只是一个模型类,其中包含项目属性和 toJson、fromJson 区域,由 json_serialized 管理。
存储类别:
class Storage {
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/inventorylist.json');
}
Future<File> writeFile(dynamic jsonmap) async {
final file = await _localFile;
return file.writeAsString('$jsonmap');
}
}
添加新项目飞镖文件:
class AddItemButton extends ConsumerStatefulWidget {
const AddItemButton({
required this.image,
required this.mode,
required this.storage,
super.key,
});
final Storage storage;
@override
ConsumerState createState() => _AddItemButtonState();
}
class _AddItemButtonState extends ConsumerState<AddItemButton> {
late var inventoryService = ref.watch(serviceProvider);
late var currentItemList = inventoryService.fetchData();
@override
Widget build(BuildContext context) {
Item addNewItem({int? barcodeNo, required String productName}) {
int id = Random().nextInt(100);
Item newItem =
Item(id: id, productName: productName, barcodeNo: barcodeNo, isActive: true,);
inventoryService.insertItem(newItem);
print("Added $productName!");
return newItem;
}
存储对象正在 main.dart 中创建,并传递到相关的屏幕和类。添加项目按钮使用 insertItem() 函数。显示库存项目的屏幕使用 fetchData() 函数。如果需要更多说明,请告诉我。
任何改进或修复的建议都非常感谢,因为我上个月刚刚开始..
将 Riverpod 视为提供程序的组合,类似于 Flutter 的小部件组合。
您有相当多的逻辑被困在非提供者/通知者中,这会影响您获得“重建”的能力。
这是第一次使用Riverpod时的常见错误,即未正确使用
build
方法。从通知程序中的其他函数返回数据不是一个好习惯,您希望影响状态或使其无效以导致通知程序/提供程序发生更改。您不应该从其他函数返回数据。
为了正确获得所需的效果,您将需要一个新的通知程序来跟踪项目列表的状态并处理项目修改/添加。然后我们可以将这些逻辑结合在一起并观察 Riverpod 的魔力。
在您的示例中,您有一个名为
JsonInventoryService
的通知程序。它的构建方法总是只返回一项,那就是NULL ITEM。这是故障点,这需要观察负责该项目的另一个提供商。因此,当 Items Notifier 更改时,JsonInventoryService 将重建,因为它正在监视该通知程序。
这里是我们如何更改此代码的方法,以便您对
ref.watch
的使用能够正确触发。我没有编译这段代码,但它应该能传达这个想法。
原创
@riverpod
class JsonInventoryService extends _$JsonInventoryService {
late Future<List<Item>> _currentItems;
late InventoryResult inventoryResult;
@override
Future<List<Item>> build() {
return Future.value([Item(id: 0, productName: 'NULL ITEM'),]);
}
Future loadItems() async {
var jsonString = await rootBundle.loadString('assets/inventorylist.json');
inventoryResult =
InventoryResult.fromJson(jsonDecode(jsonString));
_currentItems = Future.value(inventoryResultsToItems(inventoryResult));
}
Future<List<Item>> fetchData() async {
return _currentItems;
}
已修改
@riverpod
class ItemsService extends _$ItemsService {
Future<List<Item>> build() async {
final jsonString = await rootBundle.loadString('assets/inventorylist.json');
final inventoryResult = InventoryResult.fromJson(jsonDecode(jsonString));
return inventoryResultsToItems(inventoryResult);
}
Future<void> addItem(Item item) async {
//Makes a copy of the existing state list
final current = List.from(state);
current.add(item);
//Updates the state such that it includes the new item
//Causes a rebuild of anything watching via ref.watch
state = current;
}
}
@riverpod
class JsonInventoryService extends _$JsonInventoryService {
@override
Future<List<Item>> build() async {
final items = await ref.watch(itemsService.future);
if(items.isEmpty) {
return [Item(id: 0, productName: 'NULL ITEM'),];
} else {
return items;
}
}
您现在应该能够在添加附加项目时获得反应性,并且您的 JsonInventoryService 应该重建。