flutter and bloc asynchronous yield

Issue

I am using flutter with the BLoC pattern (with the flutter_bloc library) and I have these events:

PersonalFileAddedEvent(File file), PersonalFileUploadEvent(PersonalFile file) (both extend from PersonalFileEvent)

File is a file from the file picker, PersonalFile is a class that has these enum statuses: READY_TO_UPLOAD, UPLOADING, UPLOAD_FINISHED.

And this status from the BLoC:

PersonalFileListLoadedState(List<PersonalFile> files) (extend from PersonalFileListState)

When the user selects a file, the UI calls the event PersonalFileAddedEvent and passes it to the BLoC which creates a PersonalFile object and sets it’s status to READY_TO_UPLOAD. This PersonalFile object gets
added to a list which holds all the PersonalFile’s that the user is adding (and uploading). The BLoC then responds (yield) with the PersonalFileListLoadedState(blocPersonalFileList) to the UI to render the information.

Once added, an “upload now” button gets rendered in the UI for that PersonalFile. When pressed, this calls the PersonalFileUploadEvent event and sends along the PersonalFile to the BLoC to start the upload process (multipart upload).
Immediately after receiving the event, the BLoC updates this PersonalFile’s status to UPLOADING and yield the PersonalFileListLoadedState state with the PersonalFile’s status updated for the UI to show that it is uploading.

The method that uploads the multipart file is async:

Future<PersonalFile> upload(PersonalFile file) async { //upload code }

This is the mapEventToState from flutter_bloc:

Stream<PersonalFileListState> mapEventToState(PersonalFileEvent event) async* {}

Inside this mapEventToState method I am awaiting the upload method to update the PersonalFile’s status to UPLOAD_FINISHED.

The problem starts now, as the user adds several files from the file picker, and presses all the “upload” buttons. The BLoC gets blocked after receiving the first event and processes the events “synchronous like” and the UI
remains as if the other’s PersonalFile’s “upload” button were not pressed until the first one finishes (then the next one, and so on).

After one event gets fully processed (the upload completes), the next one gets processed, which makes sense since I am awaiting for the upload method to finish.

How can I write this code so that if the user presses several “upload” buttons in the UI, the BLoC does not get blocked (and thus the UI because the BLoC is unable to yield the new state) and all the files get uploaded
in parallel but only until each one finishes the BLoC sends the new List of PersonalFile with their status changed to UPLOAD_FINISHED?

I have tried changing the upload method’s signature to:

Stream<PersonalFile> upload(PersonalFile file) async* { //upload code }

and using:

.then((file) { yield PersonalFileListLoadedState(listWithUpdatedPersonalFileStatus) })

but the code inside never gets executed. I tried debug but I cannot reach the breakpoint.

Solution

Not sure how are you calling the bloc to start the process upload.
But if you are using bloc.add(event) when the button is pressed it should be processed in an asyncronous way and yield the new statuses as needed.

Also notice that when you are processing the status change if the same state is yielded several times, the listener will listen to it only once so you wont see more than one update in your UI.

Hope this helps.

Answered By – Frank

Answer Checked By – Robin (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *