File upload and download are common tasks in many Flutter apps. Managing progress, cancellations, and errors while keeping the UI responsive can be challenging. By combining BLoC with Dio (or http), you can build a clean, reactive system that handles upload/download operations with ease. This guide covers everything from setting up a repository with progress tracking to managing cancellation and showing real‑time progress in the UI.
Why Use BLoC for Upload/Download?
- Reactive UI – Progress updates automatically drive UI changes.
- Separation of concerns – Network logic stays in repositories, UI only reacts to state.
- Cancellation support – BLoC can easily cancel ongoing requests.
- Error handling – Dedicated error states provide user feedback.
- Testability – Repositories and blocs can be unit‑tested with mocked clients.
Dependencies
- Upload Implementation
We'll create a repository that uses Dio to upload a file. The repository will expose a stream for progress updates and return a Future that completes when the upload finishes.
- Download Implementation
UI Integration
Now we can use these blocs in our UI. For upload, we can pick a file and start the upload with progress indicator and cancel button.
Handling Multiple Files
For multiple uploads/downloads, you may want to have separate blocs per item or keep a list of states in a single bloc. Using a map of CancelTokens and progress streams can help manage concurrent operations.
Best Practices
- Use
CancelToken– Always allow cancellation for long‑running uploads/downloads. - Handle network errors – Show user‑friendly messages and allow retry.
- Provide progress feedback – Use
LinearProgressIndicatoror similar to keep users informed. - Dispose of resources – Cancel any pending requests in
disposeof the bloc or widget. - Use
Equatable– To avoid unnecessary UI rebuilds. - Test with mocked Dio – Use
MockClientorDiowithHttpClientAdapterfor testing. - Request permissions – For Android, you may need
WRITE_EXTERNAL_STORAGEor scoped storage permissions for downloads.
Common Mistakes
- ❌ Not cancelling tokens when the screen is disposed – May cause memory leaks or crashes.
✅ Cancel in
close()or dispose of bloc. - ❌ Not handling
CancelToken.isCancel– May show error messages for cancelled requests. ✅ Check and handle gracefully. - ❌ Not checking storage permissions – Download may fail on Android 10+. ✅ Request permissions or use scoped storage.
- ❌ Blocking UI with large files – Use
onSendProgressandonReceiveProgressto keep UI responsive. - ❌ Using
setStateinside progress callbacks – May cause rebuilds outside the widget tree. ✅ Emit states from the bloc and rebuild viaBlocBuilder.
Conclusion
BLoC provides an elegant way to handle file uploads and downloads in Flutter. By combining it with Dio's progress and cancellation capabilities, you can build responsive, user‑friendly interfaces that keep the user informed about long‑running operations. The pattern scales well for multiple files and can be easily tested. Remember to always provide feedback and cancellation options for a great user experience.