提问人:N.K. 提问时间:11/11/2023 最后编辑:N.K. 更新时间:11/15/2023 访问量:20
BlocListener 未更新,原因不明
BlocListener not being updated for unknown reason
问:
我在 BLoC 方面遇到了一些非常奇怪的问题。我正在做一些不被认为是最佳实践的事情(在肘之间共享数据),但我相信肘仍然应该按预期工作。
我在 SelectMultipleCubit 中有这个方法 activate():
class SelectMultipleCubit extends Cubit<SelectMultipleState> {
SelectMultipleCubit(this.folderViewCubit, this.fileExplorerCubit) : super(SelectMultipleInitial());
final FolderViewCubit folderViewCubit;
final FileExplorerCubit fileExplorerCubit;
以下是修改后的版本:activate()
void activate(ListItem selectedItem) async {
emit(SelectMultipleLoading());
try {
// Get the parent ID and type of the selected item
String parentId;
dynamic selectedObject;
if (selectedItem.item is Folder) {
parentId = (selectedItem.item as Folder).parentId;
selectedObject = selectedItem.item as Folder;
} else if (selectedItem.item is Receipt) {
parentId = (selectedItem.item as Receipt).parentId;
selectedObject = selectedItem.item as Receipt;
} else {
emit(SelectMultipleError());
return;
}
List<Object> items = List.from(folderViewCubit.cachedCurrentlyDisplayedFiles);
// Remove the selected item from the list
items.removeWhere((element) {
if (element is Folder && selectedObject is Folder) {
return element.id == selectedObject.id;
} else if (element is Receipt && selectedObject is Receipt) {
return element.id == selectedObject.id;
}
return false;
});
print('items: ${items.length}');
// Convert items to ListItems
List<ListItem> listItems =
items.map((item) => ListItem(item: item)).toList();
print('listItems: ${listItems.length}');
emit(SelectMultipleActivated(
items: listItems, initiallySelectedItem: selectedItem));
} on Exception catch (e) {
print(e.toString());
emit(SelectMultipleError());
}
}
这是其原始版本,不使用来自其他肘的缓存文件。activate()
void activate(ListItem selectedItem) async {
emit(SelectMultipleLoading());
try {
// Get the parent ID and type of the selected item
String parentId;
dynamic selectedObject;
if (selectedItem.item is Folder) {
parentId = (selectedItem.item as Folder).parentId;
selectedObject = selectedItem.item as Folder;
} else if (selectedItem.item is Receipt) {
parentId = (selectedItem.item as Receipt).parentId;
selectedObject = selectedItem.item as Receipt;
} else {
emit(SelectMultipleError());
return;
}
// setting last order & column values
final String lastColumn = _prefs.getLastColumn();
final String lastOrder = _prefs.getLastOrder();
List<Object> items;
switch (lastColumn) {
case 'price':
final List<FolderWithPrice> foldersWithPrice = await DatabaseRepository.instance.getFoldersByPrice(parentId, lastOrder);
final List<ReceiptWithPrice> receiptsWithPrices = await DatabaseRepository.instance.getReceiptsByPrice(parentId, lastOrder);
items = [...foldersWithPrice, ...receiptsWithPrices];
break;
case 'storageSize':
final List<FolderWithSize> foldersWithSize = await DatabaseRepository.instance.getFoldersByTotalReceiptSize(parentId, lastOrder);
final List<ReceiptWithSize> receiptsWithSize = await DatabaseRepository.instance.getReceiptsBySize(parentId, lastOrder);
items = [...foldersWithSize, ...receiptsWithSize];
break;
default:
final List<Folder> folders = await DatabaseRepository.instance.getFoldersInFolderSortedBy(parentId, lastColumn, lastOrder);
final List<Receipt> receipts = await DatabaseRepository.instance.getReceiptsInFolderSortedBy(parentId, lastColumn, lastOrder);
items = [...folders, ...receipts];
break;
}
// Remove the selected item from the list
items.removeWhere((element) {
if (element is Folder && selectedObject is Folder) {
return element.id == selectedObject.id;
} else if (element is Receipt && selectedObject is Receipt) {
return element.id == selectedObject.id;
}
return false;
});
// Convert items to ListItems
List<ListItem> listItems =
items.map((item) => ListItem(item: item)).toList();
emit(SelectMultipleActivated(
items: listItems, initiallySelectedItem: selectedItem));
} on Exception catch (e) {
...
}
}
现在在我的 UI 中,我有这个 BlocListener tp 填充一个可选项目列表:
@override
Widget build(BuildContext context) {
return BlocListener<SelectMultipleCubit, SelectMultipleState>(
listener: (context, state) {
if (state is SelectMultipleActivated) {
// this code should only run once, when the SelectMultipleView is setup
// currently SelectMultipleActivated is only emitted once so it is fine
final initiallySelectedListItem = state.initiallySelectedItem;
final restOfListItems = state.items;
// adding initially selected item to currentlySelectedListItems
currentlySelectedListItemsNotifier.value.add(initiallySelectedListItem);
// adding initially selected item to allItems first
allItems.add(initiallySelectedListItem);
// adding rest of folder contents to allItems
allItems.addAll(restOfListItems);
}
if (state is SelectMultipleActionSuccess) {
Navigator.of(context).pop();
}
},
我发现使用print语句,该侦听器不会与修改后的版本一起运行,但它确实与activate()的原始版本一起运行。activate()
我不知道为什么会这样,我也不明白为什么会这样。我希望侦听器使用原始和修改后的 activate() 方法运行。
谁能帮我确定为什么不是这种情况?
答:
0赞
N.K.
11/15/2023
#1
问题摘要:
activate() 实际上不包含任何异步代码。添加 await 意味着 init() 调用后不会立即发出 SelectMultipleInitial、SelectMultipleLoading、SelectMultipleActivated,这意味着没有足够的时间调用 SelectMultipleView build() 方法,因此 BlocListener 尚未插入到小部件树中,导致监听器无法响应任何状态。
溶液: 将 BlocListener 移至 initState()
class _SelectMultipleViewState extends State<SelectMultipleView>
@override
void initState() {
super.initState();
// only listening to state here since activate() is NOT async
final selectMultipleCubitState = context.read<SelectMultipleCubit>().state;
if (selectMultipleCubitState is SelectMultipleActivated) {
// this code should only run once, when the SelectMultipleView is setup
// currently SelectMultipleActivated is only emitted once so it is fine
final initiallySelectedListItem =
selectMultipleCubitState.initiallySelectedItem;
final restOfListItems = selectMultipleCubitState.items;
// adding initially selected item to currentlySelectedListItems
currentlySelectedListItemsNotifier.value.add(initiallySelectedListItem);
// adding initially selected item to allItems first
allItems.add(initiallySelectedListItem);
// adding rest of folder contents to allItems
allItems.addAll(restOfListItems);
}
}
评论