Flutter 库存管理:从 json 资产文件中读取,写入本地文件并添加到 Riverpod 管理的项目列表中

问题描述 投票:0回答:1

我正在尝试通过实现库存应用程序来学习 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() 函数。如果需要更多说明,请告诉我。

任何改进或修复的建议都非常感谢,因为我上个月刚刚开始..

android json flutter dart flutter-dependencies
1个回答
0
投票

将 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 应该重建。

© www.soinside.com 2019 - 2024. All rights reserved.