异步迭代列表并发出状态更改
我正在尝试上传附件列表并在迭代时更新每个元素的状态。如果上传成功完成,我们会发出 uploadSucceded = true,否则发出 false。
Future<void> uploadAttachments() async {
int uploadableAttachmentIndex = 0;
emit(state.copyWith(isUploadingAttachments: true));
final attachments = generateFormAttachmentList();
await Future.forEach(
attachments,
(UploadableAttachment attachment) async {
final success = await uploadFile(attachment);
if (success) {
debugPrint('SUCCESS!!!!!');
emit(state.copyWith(
uploadableAttachments: state.uploadableAttachments!
..[uploadableAttachmentIndex].uploadSucceded = true,
));
} else {
debugPrint('FAILED!!!');
emit(state.copyWith(
uploadableAttachments: state.uploadableAttachments!
..[uploadableAttachmentIndex].uploadSucceded = false,
isUpdatingTask: false,
taskUpdateError: 'Error uploading attachment',
attachmentUploadsFailed: true));
}
uploadableAttachmentIndex++;
}
);
emit(state.copyWith(isUploadingAttachments: false));
}
设置值后,直到我们在函数末尾点击发射,才会触发重建,从而导致上传的状态立即重新构建。我不确定为什么 forEach 内部的重建没有触发,但我认为问题出在这个函数上。块构建器如下所示:
class _UploadAttachmentsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<TaskDetailsCubit, TaskDetailsState>(builder: (context, state) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
state.attachmentUploadsFailed
? _UploadErrorWidget()
: _UploadPageHeader(state.isUploadingAttachments),
SizedBox(height: 40),
Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: state.uploadableAttachments!.length,
itemBuilder: (context, index) {
return _UploadProgressListItem(file: state.uploadableAttachments![index]);
},
),
),
],
);
});
}
}
设置 uploadSucceded 后,应该重建 UploadProgressListItem。
class _UploadProgressListItem extends StatelessWidget {
final UploadableAttachment file;
_UploadProgressListItem({required this.file});
Widget getListTileIcon() {
if (file.uploadSucceded == true)
return Icon(Icons.check, color: CoreTheme.green);
else if (file.uploadSucceded == false)
return Icon(Icons.error, color: CoreTheme.error);
else
return CircularProgressIndicator();
}
Widget getSubtitle() {
if (file.uploadSucceded == true)
return Text(
'Complete',
style: CoreTheme.textStyleLabel(color: FontColor.green),
);
else if (file.uploadSucceded == false)
return Text(
'Problem Uploading',
style: CoreTheme.textStyleLabel(color: FontColor.red),
);
else
return Text('Uploading', style: CoreTheme.textStyleLabel());
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(14.0),
child: ListTile(
leading: getListTileIcon(),
title: Text(
file.filename,
overflow: TextOverflow.ellipsis,
style: CoreTheme.textStyleBodyRegular(),
),
subtitle: getSubtitle(),
),
);
}
}
class UploadableAttachment {
bool? uploadSucceded;
final File file;
final String filename;
final String fieldKey;
UploadableAttachment({
this.uploadSucceded,
required this.file,
required this.filename,
required this.fieldKey,
});
}
我想知道我是否采取了错误的异步路线。我应该使用流而不是列表吗?我应该使用 BlocListener 或 BlocConsumer 而不是 BlocBuilder 吗?
I'm trying to upload a list of attachments and update the status of each element as they are iterated through. If the upload was completed successfully, we emit uploadSucceded = true, else false.
Future<void> uploadAttachments() async {
int uploadableAttachmentIndex = 0;
emit(state.copyWith(isUploadingAttachments: true));
final attachments = generateFormAttachmentList();
await Future.forEach(
attachments,
(UploadableAttachment attachment) async {
final success = await uploadFile(attachment);
if (success) {
debugPrint('SUCCESS!!!!!');
emit(state.copyWith(
uploadableAttachments: state.uploadableAttachments!
..[uploadableAttachmentIndex].uploadSucceded = true,
));
} else {
debugPrint('FAILED!!!');
emit(state.copyWith(
uploadableAttachments: state.uploadableAttachments!
..[uploadableAttachmentIndex].uploadSucceded = false,
isUpdatingTask: false,
taskUpdateError: 'Error uploading attachment',
attachmentUploadsFailed: true));
}
uploadableAttachmentIndex++;
}
);
emit(state.copyWith(isUploadingAttachments: false));
}
While the values get set, a rebuild isnt triggered until we hit the emit at the end of the function, causing the status of the uploads to be re-built all at once. I'm not sure why the rebuild inside the forEach isnt triggering, but I think the problem is with this function. Here is what the bloc builder looks like:
class _UploadAttachmentsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<TaskDetailsCubit, TaskDetailsState>(builder: (context, state) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
state.attachmentUploadsFailed
? _UploadErrorWidget()
: _UploadPageHeader(state.isUploadingAttachments),
SizedBox(height: 40),
Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: state.uploadableAttachments!.length,
itemBuilder: (context, index) {
return _UploadProgressListItem(file: state.uploadableAttachments![index]);
},
),
),
],
);
});
}
}
The UploadProgressListItem should be rebuilding when uploadSucceded gets set.
class _UploadProgressListItem extends StatelessWidget {
final UploadableAttachment file;
_UploadProgressListItem({required this.file});
Widget getListTileIcon() {
if (file.uploadSucceded == true)
return Icon(Icons.check, color: CoreTheme.green);
else if (file.uploadSucceded == false)
return Icon(Icons.error, color: CoreTheme.error);
else
return CircularProgressIndicator();
}
Widget getSubtitle() {
if (file.uploadSucceded == true)
return Text(
'Complete',
style: CoreTheme.textStyleLabel(color: FontColor.green),
);
else if (file.uploadSucceded == false)
return Text(
'Problem Uploading',
style: CoreTheme.textStyleLabel(color: FontColor.red),
);
else
return Text('Uploading', style: CoreTheme.textStyleLabel());
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(14.0),
child: ListTile(
leading: getListTileIcon(),
title: Text(
file.filename,
overflow: TextOverflow.ellipsis,
style: CoreTheme.textStyleBodyRegular(),
),
subtitle: getSubtitle(),
),
);
}
}
class UploadableAttachment {
bool? uploadSucceded;
final File file;
final String filename;
final String fieldKey;
UploadableAttachment({
this.uploadSucceded,
required this.file,
required this.filename,
required this.fieldKey,
});
}
I'm wondering if Im taking the wrong asynchronous route. Should I be using a stream instead of a list? Should I be using a BlocListener or BlocConsumer instead of BlocBuilder?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以使用 UploadableAttachment 类中的方法添加副本。
首先检查索引后,上传值是什么,然后您应该添加一个参数,例如正在加载,因为如果您在列表中添加一些项目,并且在 cubit 或 bloc 不更新后,它将立即更新(参考添加的自动性)值不显示新数据。最后,我一般会为这个问题添加加载参数。
You can add a copy with the method in UploadableAttachment class.
After firstly checking the index what is the upload value then you should be added a parameter, for instance, is loading because if you add some item in the list and it'll be immediately updated (reference added automaticity) value after cubit or bloc doesn't show new data. Finally, I generally added is loading parameter for this problem.